@mengruo/dsh-vision-toolkit 0.1.4 → 0.1.6-beta.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 +11 -70
- package/README.zh.md +11 -69
- package/assets/1.mp4 +0 -0
- package/assets/skill/SKILL.md +37 -5
- package/docs/plan-per-tool-visibility.md +82 -0
- package/lib/client.js +157 -6
- package/lib/client.js.map +1 -1
- package/lib/config.js +52 -0
- package/lib/config.js.map +1 -1
- package/lib/exposure.js +35 -8
- package/lib/exposure.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/object-storage.js +141 -0
- package/lib/object-storage.js.map +1 -0
- package/lib/paths.js +9 -0
- package/lib/paths.js.map +1 -1
- package/lib/runtime.js +314 -27
- package/lib/runtime.js.map +1 -1
- package/lib/tools.js +116 -4
- package/lib/tools.js.map +1 -1
- package/lib/types/client/index.d.ts +62 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/config.d.ts +59 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/exposure.d.ts +14 -2
- package/lib/types/exposure.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/object-storage.d.ts +54 -0
- package/lib/types/object-storage.d.ts.map +1 -0
- package/lib/types/paths.d.ts +7 -0
- package/lib/types/paths.d.ts.map +1 -1
- package/lib/types/runtime.d.ts +50 -0
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/tools.d.ts +22 -1
- package/lib/types/tools.d.ts.map +1 -1
- package/lib/types/upstream.d.ts +1 -0
- package/lib/types/upstream.d.ts.map +1 -1
- package/lib/types/video.d.ts +78 -0
- package/lib/types/video.d.ts.map +1 -0
- package/lib/types/web.d.ts +8 -0
- package/lib/types/web.d.ts.map +1 -1
- package/lib/upstream.js +3 -0
- package/lib/upstream.js.map +1 -1
- package/lib/video.js +169 -0
- package/lib/video.js.map +1 -0
- package/lib/web.js +78 -6
- package/lib/web.js.map +1 -1
- package/package.json +4 -1
- package/src/client/index.tsx +222 -6
- package/src/config.ts +110 -0
- package/src/exposure.ts +34 -9
- package/src/index.ts +10 -5
- package/src/object-storage.ts +174 -0
- package/src/paths.ts +11 -0
- package/src/runtime.ts +332 -25
- package/src/tools.ts +144 -3
- package/src/upstream.ts +4 -0
- package/src/video.ts +222 -0
- package/src/web.ts +93 -7
- package/vendor/agent-vision-toolkit/UPSTREAM_MANIFEST.json +11 -11
- package/vendor/agent-vision-toolkit/__pycache__/detect.cpython-314.pyc +0 -0
- package/vendor/agent-vision-toolkit/__pycache__/ground.cpython-314.pyc +0 -0
- package/vendor/agent-vision-toolkit/__pycache__/vision_client.cpython-314.pyc +0 -0
- package/vendor/agent-vision-toolkit/bin/__pycache__/glancecpython-314.pyc +0 -0
- package/vendor/agent-vision-toolkit/bin/glance +8 -1
- package/vendor/agent-vision-toolkit/detect.py +13 -7
- package/vendor/agent-vision-toolkit/ground.py +43 -18
- package/vendor/agent-vision-toolkit/tests/test_vision_client.py +88 -0
- package/vendor/agent-vision-toolkit/vision_client.py +84 -6
- package/assets/community-group-qr.png +0 -0
- package/assets/logo_aihubmix.png +0 -0
- package/assets/logo_eapi_dark.png +0 -0
- package/assets/wechat-reward.png +0 -0
package/lib/client.js
CHANGED
|
@@ -87,6 +87,8 @@ const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKi
|
|
|
87
87
|
const BUILT_IN_FREE_VISION_BASE_URL = 'https://vision.anionex.me/v1';
|
|
88
88
|
const BUILT_IN_FREE_VISION_CREDENTIAL = 'ANIONEX_FREE_VISION';
|
|
89
89
|
const BUILT_IN_FREE_VISION_MODEL = 'gemini-3.7-flash';
|
|
90
|
+
// Fixed credential reference holding the combined "accessKeyId:secretAccessKey".
|
|
91
|
+
const OBJECT_STORAGE_CREDENTIAL = 'VISION_OBJECT_STORAGE';
|
|
90
92
|
const en = {
|
|
91
93
|
nav: 'Vision',
|
|
92
94
|
settingsTitle: 'Vision Toolkit',
|
|
@@ -97,6 +99,7 @@ const en = {
|
|
|
97
99
|
providers: 'Vision providers',
|
|
98
100
|
name: 'Label',
|
|
99
101
|
enabled: 'Enabled',
|
|
102
|
+
disabled: 'Disabled',
|
|
100
103
|
priority: 'Priority {index}',
|
|
101
104
|
attempts: 'Attempts',
|
|
102
105
|
attemptsHint: 'Total attempts against this provider before failing over to the next one.',
|
|
@@ -125,6 +128,12 @@ const en = {
|
|
|
125
128
|
anthropicThinking: 'Anthropic thinking',
|
|
126
129
|
anthropicThinkingHint: 'omit has the broadest compatibility. Use disabled or adaptive only when the selected model documents that mode; restore omit first after HTTP 400.',
|
|
127
130
|
userAgent: 'User-Agent',
|
|
131
|
+
stream: 'Streaming',
|
|
132
|
+
streamHint: 'Request a streamed (SSE) completion instead of one JSON response. Use it for endpoints with weak non-streaming support or that time out on long outputs.',
|
|
133
|
+
uploadViaUrl: 'Transfer images via URL',
|
|
134
|
+
uploadViaUrlHint: 'Upload each image to the configured object storage and send the model a URL instead of base64. Requires object storage (below); region crops fall back to base64.',
|
|
135
|
+
videoSupport: 'Enable video support',
|
|
136
|
+
videoSupportHint: 'OpenAI-compatible video understanding. This setting is hidden for Anthropic providers and is currently a placeholder with no effect yet.',
|
|
128
137
|
language: 'Output language',
|
|
129
138
|
limits: 'Timeout and concurrency',
|
|
130
139
|
timeout: 'Request timeout (ms)',
|
|
@@ -150,10 +159,24 @@ const en = {
|
|
|
150
159
|
storageDirHint: 'Leave blank to keep .dsh-vision-toolkit in each workspace. On POSIX systems, set an absolute shared root such as /tmp/dsh-vision-toolkit to store artifacts, pasted images, and caches in an automatically generated per-user, workspace-specific child directory. Windows shared roots remain disabled until their ACLs can be verified safely.',
|
|
151
160
|
allowedDirs: 'Additional allowed directories',
|
|
152
161
|
allowedDirsHint: 'One path per line. The session workspace is always allowed.',
|
|
162
|
+
objectStorage: 'Object storage',
|
|
163
|
+
objectStorageHint: 'S3-compatible storage used when a provider enables URL image transfer. The access key is stored as a DSH credential and never shown again after saving.',
|
|
164
|
+
storageEndpoint: 'Endpoint',
|
|
165
|
+
storageBucket: 'Bucket',
|
|
166
|
+
storageAccessKeyId: 'Access Key ID',
|
|
167
|
+
storageSecretAccessKey: 'Secret Access Key',
|
|
168
|
+
storagePublicBase: 'Public base URL (optional)',
|
|
169
|
+
storagePublicBaseHint: 'Custom domain or r2.dev URL for permanent public links. Leave blank to use temporary presigned URLs.',
|
|
170
|
+
testStorage: 'Test object storage',
|
|
171
|
+
testingStorage: 'Testing…',
|
|
172
|
+
storageKeyPair: 'Access Key ID and Secret Access Key must both be filled together.',
|
|
153
173
|
save: 'Save and apply',
|
|
154
174
|
saving: 'Validating runtime…',
|
|
155
175
|
reload: 'Reload',
|
|
156
176
|
saved: 'Settings validated and applied.',
|
|
177
|
+
unsavedChanges: 'Changed but not saved',
|
|
178
|
+
discardChanges: 'Discard changes',
|
|
179
|
+
noUnsavedChanges: 'Settings unchanged',
|
|
157
180
|
readOnly: 'Service settings are read-only. A writable API key can still be saved.',
|
|
158
181
|
configured: 'Configured',
|
|
159
182
|
missing: 'Missing',
|
|
@@ -165,8 +188,10 @@ const en = {
|
|
|
165
188
|
runHealth: 'Run health check',
|
|
166
189
|
testConnection: 'Test API connection',
|
|
167
190
|
testModel: 'Test vision model',
|
|
191
|
+
testVideo: 'Test video call',
|
|
168
192
|
testing: 'Checking…',
|
|
169
193
|
testingModel: 'Testing model…',
|
|
194
|
+
testingVideo: 'Testing video…',
|
|
170
195
|
connectionHint: 'The API connection test only queries GET /models. The vision model test sends the bundled diagnostic image and verifies one real multimodal request.',
|
|
171
196
|
saveBeforeTesting: 'Save service changes before testing the connection.',
|
|
172
197
|
advanced: 'Advanced settings',
|
|
@@ -175,6 +200,14 @@ const en = {
|
|
|
175
200
|
hiddenVariants: 'Transparent variant routing',
|
|
176
201
|
hiddenVariantsLabel: 'Keep the original model names and enable images automatically',
|
|
177
202
|
hiddenVariantsHint: 'Text-only models keep one model-selector entry with the original name while the session runs on the image-capable variant. Pasted images, image history, and the built-in read_image tool keep working; disable to restore the explicit (Vision Toolkit) entries.',
|
|
203
|
+
toolVisibility: 'Tool visibility',
|
|
204
|
+
toolVisibilityHint: 'Which groups of vision tools an Agent sees. Applies to the next Agent conversation: an already-active Agent keeps its activation-time set until it is reloaded.',
|
|
205
|
+
toolVisibilityLocal: 'Local tools',
|
|
206
|
+
toolVisibilityLocalHint: 'trace / crop / pixel diff / foreground / colors / HTML screenshot / video info. Local processing, no on-line parallel limits.',
|
|
207
|
+
toolVisibilityOnline: 'Online image tools',
|
|
208
|
+
toolVisibilityOnlineHint: 'glance / ground / detect / long-screenshot OCR, plus the concurrency/status probe. On-line service calls share the session concurrency budget.',
|
|
209
|
+
toolVisibilityVideo: 'Video tools',
|
|
210
|
+
toolVisibilityVideoHint: 'video understanding (experimental). Calling it without an enabled video-capable service returns "video understanding unavailable".',
|
|
178
211
|
pluginVersion: 'Plugin',
|
|
179
212
|
upstreamVersion: 'Upstream',
|
|
180
213
|
activeGeneration: 'Runtime generation',
|
|
@@ -310,6 +343,7 @@ const zh = {
|
|
|
310
343
|
providers: '视觉服务列表',
|
|
311
344
|
name: '名称',
|
|
312
345
|
enabled: '启用',
|
|
346
|
+
disabled: '禁用',
|
|
313
347
|
priority: '优先级 {index}',
|
|
314
348
|
attempts: '尝试次数',
|
|
315
349
|
attemptsHint: '该服务在故障转移到下一个之前最多尝试的次数。',
|
|
@@ -338,6 +372,12 @@ const zh = {
|
|
|
338
372
|
anthropicThinking: 'Anthropic thinking',
|
|
339
373
|
anthropicThinkingHint: 'omit 兼容性最好。仅当所选模型明确支持时使用 disabled 或 adaptive;遇到 HTTP 400 时先恢复 omit。',
|
|
340
374
|
userAgent: 'User-Agent',
|
|
375
|
+
stream: '流式请求',
|
|
376
|
+
streamHint: '以流式(SSE)方式请求补全,而非一次性返回 JSON。适合对非流式支持不佳、长输出易连接超时的端点。',
|
|
377
|
+
uploadViaUrl: '通过 URL 传输图片',
|
|
378
|
+
uploadViaUrlHint: '把每张图片上传到下方配置的对象存储,将 URL 传给模型而不是 base64。需要先配置对象存储;使用 region 裁剪时回退为 base64。',
|
|
379
|
+
videoSupport: '启用视频支持',
|
|
380
|
+
videoSupportHint: 'OpenAI 兼容接口的视频理解能力。Anthropic 服务不显示此项;当前为占位设置,尚未生效。',
|
|
341
381
|
language: '结果语言',
|
|
342
382
|
limits: '超时与并发限制',
|
|
343
383
|
timeout: '单次请求超时(毫秒)',
|
|
@@ -363,10 +403,24 @@ const zh = {
|
|
|
363
403
|
storageDirHint: '留空时继续在各工作区创建 .dsh-vision-toolkit。在 POSIX 系统上填写绝对路径共享根目录(例如 /tmp/dsh-vision-toolkit)后,产物、粘贴图片和缓存会保存到自动生成的当前用户、工作区专属子目录中。Windows 共享目录会保持禁用,直到能够安全校验 ACL 权限。',
|
|
364
404
|
allowedDirs: '允许读取的其他目录',
|
|
365
405
|
allowedDirsHint: '每行填写一个目录。当前会话的工作目录始终可以读取,无需重复填写。',
|
|
406
|
+
objectStorage: '对象存储',
|
|
407
|
+
objectStorageHint: '用于「通过 URL 传输图片」的 S3 兼容存储。访问密钥以 DSH 凭据保存,保存后不再显示。',
|
|
408
|
+
storageEndpoint: 'Endpoint',
|
|
409
|
+
storageBucket: 'Bucket',
|
|
410
|
+
storageAccessKeyId: 'Access Key ID',
|
|
411
|
+
storageSecretAccessKey: 'Secret Access Key',
|
|
412
|
+
storagePublicBase: '公网 URL 前缀(可选)',
|
|
413
|
+
storagePublicBaseHint: '自定义域名或 r2.dev 地址,用于生成永久公网链接。留空则使用临时预签名 URL。',
|
|
414
|
+
testStorage: '测试对象存储',
|
|
415
|
+
testingStorage: '测试中…',
|
|
416
|
+
storageKeyPair: 'Access Key ID 与 Secret Access Key 必须同时填写。',
|
|
366
417
|
save: '保存设置',
|
|
367
418
|
saving: '正在检查并应用…',
|
|
368
419
|
reload: '重新加载',
|
|
369
420
|
saved: '设置已保存并生效。',
|
|
421
|
+
unsavedChanges: '已更改但尚未保存',
|
|
422
|
+
discardChanges: '丢弃更改',
|
|
423
|
+
noUnsavedChanges: '设置项未变更',
|
|
370
424
|
readOnly: '服务设置来自只读配置;如果 API 密钥可写,仍可在此保存密钥。',
|
|
371
425
|
configured: '已就绪',
|
|
372
426
|
missing: '未配置',
|
|
@@ -378,8 +432,10 @@ const zh = {
|
|
|
378
432
|
runHealth: '检查本地环境',
|
|
379
433
|
testConnection: '测试 API 连接',
|
|
380
434
|
testModel: '测试视觉模型',
|
|
435
|
+
testVideo: '测试视频调用',
|
|
381
436
|
testing: '检查中…',
|
|
382
437
|
testingModel: '正在测试模型…',
|
|
438
|
+
testingVideo: '正在测试视频…',
|
|
383
439
|
connectionHint: '“测试 API 连接”只请求 GET /models;“测试视觉模型”会发送插件自带的诊断图片,验证一次真实多模态调用。',
|
|
384
440
|
saveBeforeTesting: '修改服务配置后,请先保存,再执行 API 或视觉模型测试。',
|
|
385
441
|
advanced: '高级设置',
|
|
@@ -388,6 +444,14 @@ const zh = {
|
|
|
388
444
|
hiddenVariants: '透明变体路由',
|
|
389
445
|
hiddenVariantsLabel: '保留原模型名并自动启用图片能力',
|
|
390
446
|
hiddenVariantsHint: '文本模型在模型列表中只显示原名称,会话实际运行在支持图片的变体路由上:粘贴图片、历史图片和内置 read_image 工具均可正常使用。关闭后恢复显示显式的(Vision Toolkit)条目。',
|
|
447
|
+
toolVisibility: '工具可见性',
|
|
448
|
+
toolVisibilityHint: 'Agent 可见的视觉工具分组。仅在下一个 agent 对话中生效:已激活的 agent 保持激活时的工具集,直到重载。',
|
|
449
|
+
toolVisibilityLocal: '本地工具',
|
|
450
|
+
toolVisibilityLocalHint: 'trace / crop / 像素对比 / 前景提取 / 取色 / HTML 截图 / 视频信息。本地处理,不受联机并发限制。',
|
|
451
|
+
toolVisibilityOnline: '联机图片工具',
|
|
452
|
+
toolVisibilityOnlineHint: 'glance / ground / detect / 长截图 OCR,以及并发/状态查询。联机调用共享会话并发额度。',
|
|
453
|
+
toolVisibilityVideo: '视频工具',
|
|
454
|
+
toolVisibilityVideoHint: '视频理解(测试)。调用时若没有已启用且支持视频的服务,将返回“视频理解不可用”。',
|
|
391
455
|
pluginVersion: '插件版本',
|
|
392
456
|
upstreamVersion: '工具包版本',
|
|
393
457
|
activeGeneration: '本次运行已应用',
|
|
@@ -627,6 +691,9 @@ function VisionIcon({ kind = 'scan' }) {
|
|
|
627
691
|
: 'M3 5V3h2M11 3h2v2M13 11v2h-2M5 13H3v-2M5 8h6';
|
|
628
692
|
return ((0, jsx_runtime_1.jsx)("svg", { viewBox: "0 0 16 16", width: "16", height: "16", "aria-hidden": "true", fill: "none", stroke: "currentColor", strokeWidth: "1.35", strokeLinecap: "round", strokeLinejoin: "round", children: (0, jsx_runtime_1.jsx)("path", { d: path }) }));
|
|
629
693
|
}
|
|
694
|
+
function ReloadIcon() {
|
|
695
|
+
return ((0, jsx_runtime_1.jsxs)("svg", { viewBox: "0 0 24 24", width: "14", height: "14", "aria-hidden": "true", fill: "none", stroke: "currentColor", strokeWidth: "1.6", strokeLinecap: "round", strokeLinejoin: "round", children: [(0, jsx_runtime_1.jsx)("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }), (0, jsx_runtime_1.jsx)("path", { d: "M21 3v5h-5" })] }));
|
|
696
|
+
}
|
|
630
697
|
function ToolShell({ block, title, summary, icon, children, t, }) {
|
|
631
698
|
const [open, setOpen] = (0, react_1.useState)(true);
|
|
632
699
|
const status = statusText(block, t);
|
|
@@ -871,6 +938,34 @@ class VisionSettingsController {
|
|
|
871
938
|
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
872
939
|
}
|
|
873
940
|
}
|
|
941
|
+
async testStorage() {
|
|
942
|
+
this.set({ ...this.state, action: 'test-storage', error: undefined, message: undefined });
|
|
943
|
+
try {
|
|
944
|
+
const result = await apiRequest({
|
|
945
|
+
method: 'POST',
|
|
946
|
+
headers: { 'Content-Type': 'application/json' },
|
|
947
|
+
body: JSON.stringify({ action: 'test-storage' }),
|
|
948
|
+
});
|
|
949
|
+
this.set({ ...this.state, action: undefined, storageTest: result });
|
|
950
|
+
}
|
|
951
|
+
catch (error) {
|
|
952
|
+
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
async runVideoTest(providerIndex) {
|
|
956
|
+
this.set({ ...this.state, action: 'test-video', error: undefined, message: undefined });
|
|
957
|
+
try {
|
|
958
|
+
const result = await apiRequest({
|
|
959
|
+
method: 'POST',
|
|
960
|
+
headers: { 'Content-Type': 'application/json' },
|
|
961
|
+
body: JSON.stringify({ action: 'test-video', ...(providerIndex === undefined ? {} : { providerIndex }) }),
|
|
962
|
+
});
|
|
963
|
+
this.set({ ...this.state, action: undefined, videoTest: result });
|
|
964
|
+
}
|
|
965
|
+
catch (error) {
|
|
966
|
+
this.set({ ...this.state, action: undefined, error: error instanceof Error ? error.message : String(error) });
|
|
967
|
+
}
|
|
968
|
+
}
|
|
874
969
|
async checkUpdate() {
|
|
875
970
|
this.set({ ...this.state, action: 'check-update', error: undefined, message: undefined });
|
|
876
971
|
try {
|
|
@@ -935,6 +1030,9 @@ function emptyProviderDraft(defaults) {
|
|
|
935
1030
|
protocol: 'openai',
|
|
936
1031
|
anthropicThinking: 'omit',
|
|
937
1032
|
userAgent: DEFAULT_USER_AGENT,
|
|
1033
|
+
stream: false,
|
|
1034
|
+
uploadViaUrl: false,
|
|
1035
|
+
videoSupport: false,
|
|
938
1036
|
t1Seconds: '90',
|
|
939
1037
|
t2Seconds: '90',
|
|
940
1038
|
maxImageBytes: String(defaults.maxImageBytes),
|
|
@@ -956,6 +1054,9 @@ function providerDraftOf(value, fallback, defaults) {
|
|
|
956
1054
|
protocol: source?.protocol ?? 'openai',
|
|
957
1055
|
anthropicThinking: source?.anthropicThinking ?? 'omit',
|
|
958
1056
|
userAgent: source?.userAgent ?? DEFAULT_USER_AGENT,
|
|
1057
|
+
stream: source?.stream === true,
|
|
1058
|
+
uploadViaUrl: source?.uploadViaUrl === true,
|
|
1059
|
+
videoSupport: source?.videoSupport === true,
|
|
959
1060
|
t1Seconds: String(source?.t1Seconds ?? 90),
|
|
960
1061
|
t2Seconds: String(source?.t2Seconds ?? 90),
|
|
961
1062
|
maxImageBytes: String(source?.maxImageBytes ?? defaults.maxImageBytes),
|
|
@@ -983,6 +1084,9 @@ function draftOf(value) {
|
|
|
983
1084
|
maxImageBytes: String(globalDefaults.maxImageBytes),
|
|
984
1085
|
maxImagePixels: String(globalDefaults.maxImagePixels),
|
|
985
1086
|
concurrency: String(globalDefaults.concurrency),
|
|
1087
|
+
storageEndpoint: value.objectStorage?.endpoint ?? '',
|
|
1088
|
+
storageBucket: value.objectStorage?.bucket ?? '',
|
|
1089
|
+
storagePublicBase: value.objectStorage?.publicBase ?? '',
|
|
986
1090
|
runtimeMode: value.runtime?.mode ?? 'managed',
|
|
987
1091
|
toolkitPath: value.runtime?.agentVisionToolkitPath ?? '',
|
|
988
1092
|
python: value.runtime?.python ?? '',
|
|
@@ -992,6 +1096,9 @@ function draftOf(value) {
|
|
|
992
1096
|
variantEnabled: value.imageInputVariants?.enabled ?? true,
|
|
993
1097
|
variantProviders: (value.imageInputVariants?.providers ?? []).join('\n'),
|
|
994
1098
|
variantAutoSwitch: value.imageInputVariants?.autoSwitch ?? true,
|
|
1099
|
+
toolVisibilityLocal: value.toolVisibility?.local ?? true,
|
|
1100
|
+
toolVisibilityOnline: value.toolVisibility?.online ?? true,
|
|
1101
|
+
toolVisibilityVideo: value.toolVisibility?.video ?? false,
|
|
995
1102
|
};
|
|
996
1103
|
}
|
|
997
1104
|
function positiveInteger(raw, label, t) {
|
|
@@ -1023,6 +1130,9 @@ function valueOf(draft, t) {
|
|
|
1023
1130
|
protocol: provider.protocol,
|
|
1024
1131
|
anthropicThinking: provider.anthropicThinking,
|
|
1025
1132
|
...(provider.userAgent.trim() === DEFAULT_USER_AGENT ? {} : { userAgent: provider.userAgent.trim() }),
|
|
1133
|
+
...(provider.stream ? { stream: true } : {}),
|
|
1134
|
+
...(provider.uploadViaUrl ? { uploadViaUrl: true } : {}),
|
|
1135
|
+
...(provider.videoSupport ? { videoSupport: true } : {}),
|
|
1026
1136
|
...(provider.t1Seconds.trim().length === 0 ? {} : { t1Seconds: positiveInteger(provider.t1Seconds, t('t1'), t) }),
|
|
1027
1137
|
...(provider.t2Seconds.trim().length === 0 ? {} : { t2Seconds: positiveInteger(provider.t2Seconds, t('t2'), t) }),
|
|
1028
1138
|
...(provider.maxImageBytes.trim().length === 0 ? {} : { maxImageBytes: positiveInteger(provider.maxImageBytes, t('maxBytes'), t) }),
|
|
@@ -1039,6 +1149,9 @@ function valueOf(draft, t) {
|
|
|
1039
1149
|
protocol: primary?.protocol ?? 'openai',
|
|
1040
1150
|
anthropicThinking: primary?.anthropicThinking ?? 'omit',
|
|
1041
1151
|
userAgent: primary?.userAgent.trim() || DEFAULT_USER_AGENT,
|
|
1152
|
+
stream: primary?.stream === true,
|
|
1153
|
+
uploadViaUrl: primary?.uploadViaUrl === true,
|
|
1154
|
+
videoSupport: primary?.videoSupport === true,
|
|
1042
1155
|
},
|
|
1043
1156
|
providers,
|
|
1044
1157
|
language: draft.language,
|
|
@@ -1048,6 +1161,16 @@ function valueOf(draft, t) {
|
|
|
1048
1161
|
maxImageBytes: positiveInteger(draft.maxImageBytes, t('maxBytes'), t),
|
|
1049
1162
|
maxImagePixels: positiveInteger(draft.maxImagePixels, t('maxPixels'), t),
|
|
1050
1163
|
concurrency: positiveInteger(draft.concurrency, t('concurrency'), t),
|
|
1164
|
+
...(draft.storageEndpoint.trim().length === 0 && draft.storageBucket.trim().length === 0
|
|
1165
|
+
? {}
|
|
1166
|
+
: {
|
|
1167
|
+
objectStorage: {
|
|
1168
|
+
endpoint: draft.storageEndpoint.trim(),
|
|
1169
|
+
bucket: draft.storageBucket.trim(),
|
|
1170
|
+
credential: OBJECT_STORAGE_CREDENTIAL,
|
|
1171
|
+
...(draft.storagePublicBase.trim().length === 0 ? {} : { publicBase: draft.storagePublicBase.trim() }),
|
|
1172
|
+
},
|
|
1173
|
+
}),
|
|
1051
1174
|
runtime: {
|
|
1052
1175
|
mode: draft.runtimeMode,
|
|
1053
1176
|
...(draft.runtimeMode === 'external' ? { agentVisionToolkitPath: draft.toolkitPath.trim() } : {}),
|
|
@@ -1063,6 +1186,11 @@ function valueOf(draft, t) {
|
|
|
1063
1186
|
...(draft.variantAutoSwitch ? {} : { autoSwitch: false }),
|
|
1064
1187
|
hidden: draft.hiddenVariants,
|
|
1065
1188
|
},
|
|
1189
|
+
toolVisibility: {
|
|
1190
|
+
local: draft.toolVisibilityLocal,
|
|
1191
|
+
online: draft.toolVisibilityOnline,
|
|
1192
|
+
video: draft.toolVisibilityVideo,
|
|
1193
|
+
},
|
|
1066
1194
|
};
|
|
1067
1195
|
}
|
|
1068
1196
|
function settingsDraftChanged(draft, saved, t) {
|
|
@@ -1185,6 +1313,7 @@ function LoadedSettings({ controller, t }) {
|
|
|
1185
1313
|
const [draft, setDraft] = (0, react_1.useState)(undefined);
|
|
1186
1314
|
const [selectedIndex, setSelectedIndex] = (0, react_1.useState)(0);
|
|
1187
1315
|
const [keys, setKeys] = (0, react_1.useState)({});
|
|
1316
|
+
const [storageKeys, setStorageKeys] = (0, react_1.useState)({ accessKeyId: '', secretAccessKey: '' });
|
|
1188
1317
|
const [draftError, setDraftError] = (0, react_1.useState)(undefined);
|
|
1189
1318
|
const [copiedCommand, setCopiedCommand] = (0, react_1.useState)(false);
|
|
1190
1319
|
(0, react_1.useEffect)(() => { if (state.status === 'idle')
|
|
@@ -1304,14 +1433,25 @@ function LoadedSettings({ controller, t }) {
|
|
|
1304
1433
|
return;
|
|
1305
1434
|
}
|
|
1306
1435
|
}
|
|
1436
|
+
const accessKeyId = storageKeys.accessKeyId.trim();
|
|
1437
|
+
const secretAccessKey = storageKeys.secretAccessKey.trim();
|
|
1438
|
+
if ((accessKeyId.length === 0) !== (secretAccessKey.length === 0)) {
|
|
1439
|
+
setDraftError(t('storageKeyPair'));
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1307
1442
|
const credentials = Object.entries(keys)
|
|
1308
1443
|
.filter(([, value]) => value.trim().length > 0)
|
|
1309
1444
|
.map(([ref, value]) => ({ ref, value: value.trim() }));
|
|
1445
|
+
if (accessKeyId.length > 0 && (draft.storageEndpoint.trim().length > 0 || draft.storageBucket.trim().length > 0)) {
|
|
1446
|
+
credentials.push({ ref: OBJECT_STORAGE_CREDENTIAL, value: `${accessKeyId}:${secretAccessKey}` });
|
|
1447
|
+
}
|
|
1310
1448
|
const savedRefs = new Set(credentials.map(credential => credential.ref));
|
|
1311
1449
|
setDraftError(undefined);
|
|
1312
1450
|
void controller.save(valueOf(draft, t), snapshot.settings.revision, credentials, snapshot.writable).then(saved => {
|
|
1313
1451
|
if (saved) {
|
|
1314
1452
|
setKeys(current => Object.fromEntries(Object.entries(current).filter(([ref]) => !savedRefs.has(ref))));
|
|
1453
|
+
if (savedRefs.has(OBJECT_STORAGE_CREDENTIAL))
|
|
1454
|
+
setStorageKeys({ accessKeyId: '', secretAccessKey: '' });
|
|
1315
1455
|
}
|
|
1316
1456
|
});
|
|
1317
1457
|
}
|
|
@@ -1319,6 +1459,12 @@ function LoadedSettings({ controller, t }) {
|
|
|
1319
1459
|
setDraftError(error instanceof Error ? error.message : String(error));
|
|
1320
1460
|
}
|
|
1321
1461
|
};
|
|
1462
|
+
const discard = () => {
|
|
1463
|
+
setDraft(draftOf(snapshot.settings.value));
|
|
1464
|
+
setKeys({});
|
|
1465
|
+
setStorageKeys({ accessKeyId: '', secretAccessKey: '' });
|
|
1466
|
+
setDraftError(undefined);
|
|
1467
|
+
};
|
|
1322
1468
|
const busy = state.action !== undefined;
|
|
1323
1469
|
const selectedProvider = draft.providers[selectedIndex];
|
|
1324
1470
|
const providerCredentials = snapshot.credentials ?? [];
|
|
@@ -1326,14 +1472,18 @@ function LoadedSettings({ controller, t }) {
|
|
|
1326
1472
|
const selectedKey = selectedProvider === undefined ? '' : (keys[selectedProvider.credential] ?? '');
|
|
1327
1473
|
const selectedKeyLocked = selectedCredential !== undefined && !selectedCredential.writable;
|
|
1328
1474
|
const selectedBuiltInFree = selectedCredential?.source === 'built-in-free';
|
|
1329
|
-
const
|
|
1475
|
+
const objectStorageCredential = snapshot.objectStorageCredential ?? { ref: '', configured: false, writable: false };
|
|
1476
|
+
const canSave = snapshot.writable || Object.values(keys).some(value => value.trim().length > 0) || storageKeys.accessKeyId.trim().length > 0 || storageKeys.secretAccessKey.trim().length > 0;
|
|
1330
1477
|
const runtimeErrorTitle = snapshot.runtime.ready ? t('runtimeCandidateRejected') : t('runtimeUnavailable');
|
|
1331
1478
|
const pluginUpdate = state.update;
|
|
1332
1479
|
const updateCapability = pluginUpdate ?? snapshot.release.update;
|
|
1333
1480
|
const latestVersion = pluginUpdate?.latestVersion;
|
|
1334
1481
|
const updateReason = updateCapability.reason === undefined ? undefined : t(UPDATE_REASON_KEYS[updateCapability.reason]);
|
|
1335
1482
|
const updateCheckSupported = updateCapability.checkSupported ?? updateCapability.supported;
|
|
1336
|
-
const updateHasUnsavedChanges = Object.values(keys).some(value => value.
|
|
1483
|
+
const updateHasUnsavedChanges = Object.values(keys).some(value => value.length > 0)
|
|
1484
|
+
|| storageKeys.accessKeyId.length > 0
|
|
1485
|
+
|| storageKeys.secretAccessKey.length > 0
|
|
1486
|
+
|| settingsDraftChanged(draft, snapshot.settings.value, t);
|
|
1337
1487
|
const manualUpdateProfile = updateCapability.profile ?? 'web';
|
|
1338
1488
|
const manualUpdateCommand = `dsh plugin --profile ${manualUpdateProfile} add @mengruo/dsh-vision-toolkit@latest --registry=https://registry.npmjs.org/`;
|
|
1339
1489
|
const copyManualUpdate = () => {
|
|
@@ -1352,28 +1502,29 @@ function LoadedSettings({ controller, t }) {
|
|
|
1352
1502
|
void controller.applyUpdate(latestVersion);
|
|
1353
1503
|
};
|
|
1354
1504
|
const providerHealth = state.providerHealth?.[selectedIndex];
|
|
1355
|
-
return ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-alert notice", children: t('externalNotice') }), !snapshot.writable ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('readOnly') }) : null, draftError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: draftError }), state.error === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error }), state.message === 'saved' ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('saved') }) : null, state.message === 'restarting' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('restarting', { version: state.restart.toVersion }) }) : null, state.message === 'manual-restart-required' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('manualRestartRequired', { version: state.restart.toVersion }) }) : null, snapshot.runtime.lastError === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert error", children: [(0, jsx_runtime_1.jsx)("strong", { children: runtimeErrorTitle }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.runtime.lastError })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-essential", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('providers') }), (0, jsx_runtime_1.jsx)("p", { children: t('providerHint') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-select", children: [(0, jsx_runtime_1.jsx)("select", { "aria-label": t('providers'), disabled: !snapshot.writable || busy, value: selectedIndex, onChange: (event) => { setSelectedIndex(Number(event.target.value)); }, children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("option", { value: index, children: [index + 1, ". ", provider.name.trim() || provider.model.trim() || t('provider')] }, index))) }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length >= 32, onClick: addProvider, children: t('addProvider') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length <= 1, onClick: () => { removeProvider(selectedIndex); }, children: t('removeProvider') })] }), selectedProvider === undefined ? null : ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-head", children: [(0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: selectedProvider.enabled, disabled: !snapshot.writable || busy, onChange: (event) => { updateProvider(selectedIndex, 'enabled', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('enabled') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-provider-priority", children: t('priority', { index: selectedIndex + 1 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('name'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('name'), value: selectedProvider.name, onChange: (event) => { updateProvider(selectedIndex, 'name', event.target.value); }, placeholder: selectedProvider.model || t('model') }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('model'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('model'), disabled: !snapshot.writable || busy, value: selectedProvider.model, onChange: (event) => { updateProvider(selectedIndex, 'model', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('baseUrl'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('baseUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.baseUrl, onChange: (event) => { updateProvider(selectedIndex, 'baseUrl', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('protocol'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('protocol'), disabled: !snapshot.writable || busy, value: selectedProvider.protocol, onChange: (event) => { updateProvider(selectedIndex, 'protocol', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "openai", children: "OpenAI Chat Completions" }), (0, jsx_runtime_1.jsx)("option", { value: "anthropic", children: "Anthropic Messages" })] }) }), selectedProvider.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: selectedProvider.anthropicThinking, onChange: (event) => { updateProvider(selectedIndex, 'anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('userAgent'), value: selectedProvider.userAgent, onChange: (event) => { updateProvider(selectedIndex, 'userAgent', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t1'), hint: t('t1Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t1'), inputMode: "numeric", value: selectedProvider.t1Seconds, onChange: (event) => { updateProvider(selectedIndex, 't1Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t2'), hint: t('t2Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t2'), inputMode: "numeric", value: selectedProvider.t2Seconds, onChange: (event) => { updateProvider(selectedIndex, 't2Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxBytes'), inputMode: "numeric", value: selectedProvider.maxImageBytes, onChange: (event) => { updateProvider(selectedIndex, 'maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxPixels'), inputMode: "numeric", value: selectedProvider.maxImagePixels, onChange: (event) => { updateProvider(selectedIndex, 'maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('concurrency'), inputMode: "numeric", value: selectedProvider.concurrency, onChange: (event) => { updateProvider(selectedIndex, 'concurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('attempts'), hint: t('attemptsHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('attempts'), inputMode: "numeric", value: selectedProvider.attempts, onChange: (event) => { updateProvider(selectedIndex, 'attempts', event.target.value); } }) })] }), (0, jsx_runtime_1.jsx)(Field, { label: t('apiKey'), hint: selectedBuiltInFree ? t('apiKeyBuiltInFree') : selectedKeyLocked ? t('apiKeyLocked') : t('apiKeyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('apiKey'), type: "password", autoComplete: "new-password", disabled: busy || selectedKeyLocked || selectedBuiltInFree, placeholder: selectedCredential?.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: selectedKey, onChange: (event) => { setKeys(current => ({ ...current, [selectedProvider.credential]: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-tests", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('connection', selectedIndex); }, children: state.action === 'connection' ? t('testing') : t('testConnection') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('model', selectedIndex); }, children: state.action === 'model' ? t('testingModel') : t('testModel') })] }), providerHealth === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: ['service', 'model'].map(name => {
|
|
1505
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-settings", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-save-dock", "data-dirty": updateHasUnsavedChanges ? 'true' : undefined, children: [(0, jsx_runtime_1.jsx)("button", { type: "button", className: "dvt-save-dock-reload", "aria-label": t('reload'), title: t('reload'), disabled: busy, onClick: () => { void controller.load(); }, children: (0, jsx_runtime_1.jsx)(ReloadIcon, {}) }), updateHasUnsavedChanges ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('unsavedChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy, onClick: discard, children: t('discardChanges') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: !canSave || busy, onClick: save, children: state.action === 'save' ? t('saving') : t('save') })] })) : ((0, jsx_runtime_1.jsx)("span", { className: "dvt-save-dock-text", children: t('noUnsavedChanges') }))] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert notice", children: t('externalNotice') }), !snapshot.writable ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('readOnly') }) : null, draftError === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: draftError }), state.error === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert error", children: state.error }), state.message === 'saved' ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('saved') }) : null, state.message === 'restarting' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('restarting', { version: state.restart.toVersion }) }) : null, state.message === 'manual-restart-required' && state.restart !== undefined ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert success", children: t('manualRestartRequired', { version: state.restart.toVersion }) }) : null, snapshot.runtime.lastError === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert error", children: [(0, jsx_runtime_1.jsx)("strong", { children: runtimeErrorTitle }), (0, jsx_runtime_1.jsx)("span", { children: snapshot.runtime.lastError })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-essential", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('providers') }), (0, jsx_runtime_1.jsx)("p", { children: t('providerHint') })] }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-select", children: [(0, jsx_runtime_1.jsx)("select", { "aria-label": t('providers'), disabled: !snapshot.writable || busy, value: selectedIndex, onChange: (event) => { setSelectedIndex(Number(event.target.value)); }, children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("option", { value: index, children: [index + 1, ". ", provider.name.trim() || provider.model.trim() || t('provider')] }, index))) }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length >= 32, onClick: addProvider, children: t('addProvider') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: !snapshot.writable || busy || draft.providers.length <= 1, onClick: () => { removeProvider(selectedIndex); }, children: t('removeProvider') })] }), selectedProvider === undefined ? null : ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-card", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-head", children: [(0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: selectedProvider.enabled, disabled: !snapshot.writable || busy, onChange: (event) => { updateProvider(selectedIndex, 'enabled', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('enabled') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-provider-priority", children: t('priority', { index: selectedIndex + 1 }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('name'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('name'), value: selectedProvider.name, onChange: (event) => { updateProvider(selectedIndex, 'name', event.target.value); }, placeholder: selectedProvider.model || t('model') }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('model'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('model'), disabled: !snapshot.writable || busy, value: selectedProvider.model, onChange: (event) => { updateProvider(selectedIndex, 'model', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('baseUrl'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('baseUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.baseUrl, onChange: (event) => { updateProvider(selectedIndex, 'baseUrl', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('protocol'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('protocol'), disabled: !snapshot.writable || busy, value: selectedProvider.protocol, onChange: (event) => { updateProvider(selectedIndex, 'protocol', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "openai", children: "OpenAI Chat Completions" }), (0, jsx_runtime_1.jsx)("option", { value: "anthropic", children: "Anthropic Messages" })] }) }), selectedProvider.protocol === 'anthropic' ? (0, jsx_runtime_1.jsx)(Field, { label: t('anthropicThinking'), hint: t('anthropicThinkingHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('anthropicThinking'), value: selectedProvider.anthropicThinking, onChange: (event) => { updateProvider(selectedIndex, 'anthropicThinking', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "omit", children: "omit (widest compatibility)" }), (0, jsx_runtime_1.jsx)("option", { value: "disabled", children: "disabled (model support required)" }), (0, jsx_runtime_1.jsx)("option", { value: "adaptive", children: "adaptive (model support required)" })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('userAgent'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('userAgent'), value: selectedProvider.userAgent, onChange: (event) => { updateProvider(selectedIndex, 'userAgent', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('stream'), hint: t('streamHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('stream'), disabled: !snapshot.writable || busy, value: selectedProvider.stream ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'stream', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('uploadViaUrl'), hint: t('uploadViaUrlHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('uploadViaUrl'), disabled: !snapshot.writable || busy, value: selectedProvider.uploadViaUrl ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'uploadViaUrl', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }), selectedProvider.protocol === 'openai' ? (0, jsx_runtime_1.jsx)(Field, { label: t('videoSupport'), hint: t('videoSupportHint'), children: (0, jsx_runtime_1.jsxs)("select", { "aria-label": t('videoSupport'), disabled: !snapshot.writable || busy, value: selectedProvider.videoSupport ? 'enabled' : 'disabled', onChange: (event) => { updateProvider(selectedIndex, 'videoSupport', event.target.value === 'enabled'); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "disabled", children: t('disabled') }), (0, jsx_runtime_1.jsx)("option", { value: "enabled", children: t('enabled') })] }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('t1'), hint: t('t1Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t1'), inputMode: "numeric", value: selectedProvider.t1Seconds, onChange: (event) => { updateProvider(selectedIndex, 't1Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('t2'), hint: t('t2Hint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('t2'), inputMode: "numeric", value: selectedProvider.t2Seconds, onChange: (event) => { updateProvider(selectedIndex, 't2Seconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxBytes'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxBytes'), inputMode: "numeric", value: selectedProvider.maxImageBytes, onChange: (event) => { updateProvider(selectedIndex, 'maxImageBytes', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('maxPixels'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('maxPixels'), inputMode: "numeric", value: selectedProvider.maxImagePixels, onChange: (event) => { updateProvider(selectedIndex, 'maxImagePixels', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('concurrency'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('concurrency'), inputMode: "numeric", value: selectedProvider.concurrency, onChange: (event) => { updateProvider(selectedIndex, 'concurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('attempts'), hint: t('attemptsHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('attempts'), inputMode: "numeric", value: selectedProvider.attempts, onChange: (event) => { updateProvider(selectedIndex, 'attempts', event.target.value); } }) })] }), (0, jsx_runtime_1.jsx)(Field, { label: t('apiKey'), hint: selectedBuiltInFree ? t('apiKeyBuiltInFree') : selectedKeyLocked ? t('apiKeyLocked') : t('apiKeyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('apiKey'), type: "password", autoComplete: "new-password", disabled: busy || selectedKeyLocked || selectedBuiltInFree, placeholder: selectedCredential?.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: selectedKey, onChange: (event) => { setKeys(current => ({ ...current, [selectedProvider.credential]: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-tests", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('connection', selectedIndex); }, children: state.action === 'connection' ? t('testing') : t('testConnection') }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('model', selectedIndex); }, children: state.action === 'model' ? t('testingModel') : t('testModel') }), selectedProvider.protocol === 'openai' ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "primary", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runVideoTest(selectedIndex); }, children: state.action === 'test-video' ? t('testingVideo') : t('testVideo') }) : null] }), providerHealth === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: ['service', 'model'].map(name => {
|
|
1356
1506
|
const check = providerHealth.checks[name];
|
|
1357
1507
|
if (check === undefined)
|
|
1358
1508
|
return null;
|
|
1359
1509
|
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1360
|
-
}) })
|
|
1510
|
+
}) }), state.videoTest === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: (0, jsx_runtime_1.jsxs)("div", { "data-status": "ok", children: [(0, jsx_runtime_1.jsx)("span", { children: t('videoSupport') }), (0, jsx_runtime_1.jsx)("strong", { children: t('statusOk') }), (0, jsx_runtime_1.jsx)("p", { children: state.videoTest.detail })] }) })] }))] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('prioritySort') }), (0, jsx_runtime_1.jsx)("p", { children: t('prioritySortHint') })] }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-sorter", children: draft.providers.map((provider, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "dvt-sorter-row", children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-index", children: index + 1 }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-sorter-name", children: provider.name.trim() || provider.model.trim() || t('provider') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-provider-actions", children: [(0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveUp'), title: t('moveUp'), disabled: !snapshot.writable || busy || index === 0, onClick: () => { moveProvider(index, -1); }, children: "\u2191" }), (0, jsx_runtime_1.jsx)("button", { type: "button", "aria-label": t('moveDown'), title: t('moveDown'), disabled: !snapshot.writable || busy || index === draft.providers.length - 1, onClick: () => { moveProvider(index, 1); }, children: "\u2193" })] })] }, index))) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel dvt-update-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtimeCheck') }), (0, jsx_runtime_1.jsx)("p", { children: t('runtimeCheckHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.runHealth('health'); }, children: state.action === 'health' ? t('testing') : t('runHealth') }) })] }), state.health === undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('notTested') }) : (0, jsx_runtime_1.jsx)("div", { className: "dvt-health-grid", children: ['python', 'dependencies', 'chrome'].map(name => {
|
|
1361
1511
|
const check = state.health?.checks[name];
|
|
1362
1512
|
if (check === undefined)
|
|
1363
1513
|
return null;
|
|
1364
1514
|
return (0, jsx_runtime_1.jsxs)("div", { "data-status": check.status, children: [(0, jsx_runtime_1.jsx)("span", { children: t(HEALTH_NAME_KEYS[name] ?? 'health') }), (0, jsx_runtime_1.jsx)("strong", { children: t(HEALTH_STATUS_KEYS[check.status]) }), (0, jsx_runtime_1.jsx)("p", { children: healthDetail(name, check.detail, t) })] }, name);
|
|
1365
|
-
}) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('language') }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-form-grid", children: (0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('limits') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('hardTimeout'), hint: t('hardTimeoutHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('hardTimeout'), inputMode: "numeric", value: draft.hardTimeoutSeconds, onChange: (event) => { update('hardTimeoutSeconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('sessionConcurrency'), hint: t('sessionConcurrencyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('sessionConcurrency'), inputMode: "numeric", value: draft.sessionMaxConcurrency, onChange: (event) => { update('sessionMaxConcurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('minAvailable'), hint: t('minAvailableHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('minAvailable'), inputMode: "numeric", value: draft.minAvailableSeconds, onChange: (event) => { update('minAvailableSeconds', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('storage') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageDir'), hint: t('storageDirHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageDir'), placeholder: "/tmp/dsh-vision-toolkit", value: draft.storageDir, onChange: (event) => { update('storageDir', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1515
|
+
}) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('updates') }), (0, jsx_runtime_1.jsx)("p", { children: t('updatesHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${pluginUpdate?.updateAvailable ? 'warning' : pluginUpdate !== undefined && pluginUpdate.supported ? 'ok' : ''}`, children: pluginUpdate?.updateAvailable ? t('updateAvailable') : pluginUpdate !== undefined && pluginUpdate.supported ? t('upToDate') : t('pluginVersion') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-update-grid", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateInstalled') }), (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateLatest') }), (0, jsx_runtime_1.jsx)("strong", { children: latestVersion ?? '—' })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { children: t('updateProfile') }), (0, jsx_runtime_1.jsx)("strong", { children: updateCapability.profile ?? '—' })] })] }), !updateCapability.supported ? (0, jsx_runtime_1.jsxs)("div", { className: "dvt-alert warning", children: [(0, jsx_runtime_1.jsx)("strong", { children: t('updateUnsupported') }), (0, jsx_runtime_1.jsx)("span", { children: updateReason })] }) : null, updateCapability.supported && updateHasUnsavedChanges ? (0, jsx_runtime_1.jsx)("div", { className: "dvt-alert warning", children: t('updateSaveFirst') }) : null, pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('updateAvailableDetail', { version: latestVersion }) }) : null, pluginUpdate?.supported && !pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('upToDateDetail', { version: latestVersion }) }) : null, (0, jsx_runtime_1.jsx)("p", { className: "dvt-muted", children: t('manualUpdateHint') }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-manual-update", children: [(0, jsx_runtime_1.jsx)("code", { children: manualUpdateCommand }), (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", onClick: copyManualUpdate, children: copiedCommand ? t('copied') : t('copy') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-actions", children: [(0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "outline", disabled: busy || !updateCheckSupported || state.restart !== undefined, onClick: () => { void controller.checkUpdate(); }, children: state.action === 'check-update' ? t('checkingUpdate') : t('checkUpdate') }), pluginUpdate?.supported && pluginUpdate.updateAvailable && latestVersion !== undefined ? (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { variant: "primary", disabled: busy || state.restart !== undefined || updateHasUnsavedChanges, onClick: applyUpdate, children: state.action === 'apply-update' ? t('updatingPlugin') : t('updateNow') }) : null] })] }), (0, jsx_runtime_1.jsxs)("details", { className: "dvt-advanced", children: [(0, jsx_runtime_1.jsxs)("summary", { children: [(0, jsx_runtime_1.jsxs)("span", { children: [(0, jsx_runtime_1.jsx)("strong", { children: t('advanced') }), (0, jsx_runtime_1.jsx)("small", { children: t('advancedHint') })] }), (0, jsx_runtime_1.jsx)("span", { className: "dvt-details-chevron", "aria-hidden": "true", children: "\u2304" })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-advanced-body", children: [(0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('language') }) }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-form-grid", children: (0, jsx_runtime_1.jsx)(Field, { label: t('language'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.language, onChange: (event) => { update('language', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "zh", children: "\u4E2D\u6587" }), (0, jsx_runtime_1.jsx)("option", { value: "en", children: "English" })] }) }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('limits') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('hardTimeout'), hint: t('hardTimeoutHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('hardTimeout'), inputMode: "numeric", value: draft.hardTimeoutSeconds, onChange: (event) => { update('hardTimeoutSeconds', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('sessionConcurrency'), hint: t('sessionConcurrencyHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('sessionConcurrency'), inputMode: "numeric", value: draft.sessionMaxConcurrency, onChange: (event) => { update('sessionMaxConcurrency', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('minAvailable'), hint: t('minAvailableHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('minAvailable'), inputMode: "numeric", value: draft.minAvailableSeconds, onChange: (event) => { update('minAvailableSeconds', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('imageInput') }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.hiddenVariants, disabled: !snapshot.writable || busy, onChange: (event) => { update('hiddenVariants', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('hiddenVariantsLabel') }), (0, jsx_runtime_1.jsx)("small", { children: t('hiddenVariantsHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('toolVisibility') }), (0, jsx_runtime_1.jsx)("p", { children: t('toolVisibilityHint') })] }) }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityLocal, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityLocal', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('toolVisibilityLocal') }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityLocalHint') })] }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityOnline, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityOnline', event.target.checked); } }), (0, jsx_runtime_1.jsx)("span", { children: t('toolVisibilityOnline') }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityOnlineHint') })] }), (0, jsx_runtime_1.jsxs)("label", { className: "dvt-check", children: [(0, jsx_runtime_1.jsx)("input", { type: "checkbox", checked: draft.toolVisibilityVideo, disabled: !snapshot.writable || busy, onChange: (event) => { update('toolVisibilityVideo', event.target.checked); } }), (0, jsx_runtime_1.jsxs)("span", { children: [t('toolVisibilityVideo'), " ", (0, jsx_runtime_1.jsx)("em", { children: "\uFF08\u6D4B\u8BD5\uFF09" })] }), (0, jsx_runtime_1.jsx)("small", { children: t('toolVisibilityVideoHint') })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsx)("div", { className: "dvt-panel-title", children: (0, jsx_runtime_1.jsx)("h3", { children: t('storage') }) }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageDir'), hint: t('storageDirHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageDir'), placeholder: "/tmp/dsh-vision-toolkit", value: draft.storageDir, onChange: (event) => { update('storageDir', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('allowedDirs'), hint: t('allowedDirsHint'), children: (0, jsx_runtime_1.jsx)("textarea", { rows: 3, value: draft.allowedDirs, onChange: (event) => { update('allowedDirs', event.target.value); } }) })] })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h3", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("p", { children: t('objectStorageHint') })] }), (0, jsx_runtime_1.jsx)("div", { className: "dvt-actions", children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Button, { size: "sm", variant: "outline", disabled: busy || !snapshot.runtime.ready, onClick: () => { void controller.testStorage(); }, children: state.action === 'test-storage' ? t('testingStorage') : t('testStorage') }) })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('storageEndpoint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageEndpoint'), disabled: !snapshot.writable || busy, value: draft.storageEndpoint, onChange: (event) => { update('storageEndpoint', event.target.value); }, placeholder: "https://<account>.r2.cloudflarestorage.com" }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageBucket'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageBucket'), disabled: !snapshot.writable || busy, value: draft.storageBucket, onChange: (event) => { update('storageBucket', event.target.value); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageAccessKeyId'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageAccessKeyId'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.accessKeyId, onChange: (event) => { setStorageKeys(current => ({ ...current, accessKeyId: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storageSecretAccessKey'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storageSecretAccessKey'), type: "password", autoComplete: "new-password", disabled: busy || !snapshot.writable, placeholder: objectStorageCredential.configured ? t('apiKeyPlaceholderConfigured') : t('apiKeyPlaceholderMissing'), value: storageKeys.secretAccessKey, onChange: (event) => { setStorageKeys(current => ({ ...current, secretAccessKey: event.target.value })); setDraftError(undefined); } }) }), (0, jsx_runtime_1.jsx)(Field, { label: t('storagePublicBase'), hint: t('storagePublicBaseHint'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { "aria-label": t('storagePublicBase'), disabled: !snapshot.writable || busy, value: draft.storagePublicBase, onChange: (event) => { update('storagePublicBase', event.target.value); }, placeholder: "https://cdn.example.com" }) })] }), state.storageTest === undefined ? null : (0, jsx_runtime_1.jsx)("div", { className: "dvt-provider-test-result", children: (0, jsx_runtime_1.jsxs)("div", { "data-status": "ok", children: [(0, jsx_runtime_1.jsx)("span", { children: t('objectStorage') }), (0, jsx_runtime_1.jsx)("strong", { children: t('statusOk') }), (0, jsx_runtime_1.jsx)("p", { children: state.storageTest.detail })] }) })] }), (0, jsx_runtime_1.jsxs)("section", { className: "dvt-panel", children: [(0, jsx_runtime_1.jsxs)("div", { className: "dvt-panel-title", children: [(0, jsx_runtime_1.jsx)("h3", { children: t('runtime') }), (0, jsx_runtime_1.jsx)("span", { className: `dvt-badge ${snapshot.runtime.ready ? 'ok' : 'error'}`, children: snapshot.runtime.ready ? snapshot.runtime.upstream?.source === 'managed' ? t('runtimeManaged') : snapshot.runtime.upstream?.source === 'external' ? t('runtimeExternal') : t('runtimeReady') : t('runtimeUnavailable') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-form-grid", children: [(0, jsx_runtime_1.jsx)(Field, { label: t('runtimeMode'), children: (0, jsx_runtime_1.jsxs)("select", { value: draft.runtimeMode, onChange: (event) => { update('runtimeMode', event.target.value); }, children: [(0, jsx_runtime_1.jsx)("option", { value: "managed", children: t('runtimeManaged') }), (0, jsx_runtime_1.jsx)("option", { value: "external", children: t('runtimeExternal') })] }) }), draft.runtimeMode === 'external' ? (0, jsx_runtime_1.jsx)(Field, { label: t('toolkitPath'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { value: draft.toolkitPath, onChange: (event) => { update('toolkitPath', event.target.value); } }) }) : null, (0, jsx_runtime_1.jsx)(Field, { label: t('python'), children: (0, jsx_runtime_1.jsx)(dsh_client_ui_primitives_1.Input, { placeholder: "python3", value: draft.python, onChange: (event) => { update('python', event.target.value); } }) })] }), snapshot.runtime.upstream === undefined ? null : (0, jsx_runtime_1.jsxs)("div", { className: "dvt-runtime-facts", children: [(0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.path }), (0, jsx_runtime_1.jsxs)("code", { children: [snapshot.runtime.upstream.python, " \u00B7 ", snapshot.runtime.upstream.pythonVersion] }), (0, jsx_runtime_1.jsx)("code", { children: snapshot.runtime.upstream.runtimeHome })] })] })] })] }), (0, jsx_runtime_1.jsxs)("footer", { className: "dvt-settings-footer", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("span", { className: "dvt-kicker", children: t('pluginKind') }), (0, jsx_runtime_1.jsx)("h2", { children: t('settingsTitle') }), (0, jsx_runtime_1.jsx)("p", { children: t('settingsIntro') })] }), (0, jsx_runtime_1.jsxs)("div", { className: "dvt-release", children: [(0, jsx_runtime_1.jsxs)("span", { children: [t('pluginVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.pluginVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('upstreamVersion'), " ", (0, jsx_runtime_1.jsx)("strong", { children: snapshot.release.upstreamVersion })] }), (0, jsx_runtime_1.jsxs)("span", { children: [t('activeGeneration'), " ", (0, jsx_runtime_1.jsx)("strong", { children: t('activeGenerationValue', { generation: snapshot.runtime.generation }) })] })] })] })] }));
|
|
1366
1516
|
}
|
|
1367
1517
|
const CSS = `
|
|
1368
1518
|
.dvt-tool{margin:4px 0;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-1);overflow:hidden;box-shadow:var(--dsw-shadow-lv1)}
|
|
1369
1519
|
.dvt-tool-head{width:100%;min-height:38px;display:flex;align-items:center;gap:7px;padding:8px 10px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer;font:inherit}.dvt-tool-head:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}.dvt-tool-icon{width:20px;height:20px;display:grid;place-items:center;border-radius:6px;color:var(--dsw-alias-state-business-primary);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);flex:none}.dvt-tool-title{font-size:12px;font-weight:650;white-space:nowrap}.dvt-tool-sep{opacity:.35}.dvt-tool-summary{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;color:var(--dsw-alias-label-secondary)}.dvt-tool-status{margin-left:auto;font-size:11px;color:var(--dsw-alias-label-secondary);max-width:45%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvt-tool[data-state=error] .dvt-tool-status{color:var(--dsw-alias-state-error-primary)}.dvt-chevron{margin-left:auto;transition:transform .16s ease;opacity:.55}.dvt-chevron[data-open=true]{transform:rotate(180deg)}.dvt-tool-body{padding:0 10px 10px}.dvt-stack{display:grid;gap:10px}.dvt-muted{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}
|
|
1370
1520
|
.dvt-metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.dvt-metrics>div,.dvt-diff-score{padding:10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);display:grid;gap:4px}.dvt-metrics span,.dvt-diff-score span{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--dsw-alias-label-secondary)}.dvt-metrics strong,.dvt-diff-score strong{font-size:13px}.dvt-list{list-style:none;margin:0;padding:0;display:grid;gap:4px;max-height:160px;overflow:auto}.dvt-list li{display:flex;justify-content:space-between;gap:12px;padding:6px 8px;border-radius:7px;background:var(--dsw-alias-bg-layer-2);font-size:11px}.dvt-list code{color:var(--dsw-alias-state-business-primary)}.dvt-table-wrap{max-height:220px;overflow:auto;border:1px solid var(--dsw-alias-border-l1);border-radius:9px}.dvt-table{width:100%;border-collapse:collapse;font-size:11px}.dvt-table th,.dvt-table td{padding:7px 8px;text-align:left;border-bottom:1px solid var(--dsw-alias-border-l1)}.dvt-table th{position:sticky;top:0;background:var(--dsw-alias-bg-layer-2);font-size:10px;text-transform:uppercase;letter-spacing:.05em}.dvt-table tr:last-child td{border-bottom:0}
|
|
1371
1521
|
.dvt-artifact{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;overflow:hidden;background:var(--dsw-alias-bg-layer-1)}.dvt-preview{display:block;width:100%;max-height:360px;object-fit:contain;background:repeating-conic-gradient(var(--dsw-alias-bg-module-platform) 0 25%,var(--dsw-alias-bg-layer-1) 0 50%) 50%/18px 18px;border:0}.dvt-svg{height:280px}.dvt-artifact-meta{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 10px}.dvt-artifact-meta>div:first-child{min-width:0;display:grid;gap:2px}.dvt-artifact-meta strong{font-size:12px;overflow:hidden;text-overflow:ellipsis}.dvt-artifact-meta span,.dvt-artifact-meta small{font-size:10px;color:var(--dsw-alias-label-secondary)}.dvt-actions{display:flex;align-items:center;gap:7px;flex-wrap:wrap}.dvt-download{display:inline-flex;align-items:center;height:28px;padding:0 12px;border-radius:999px;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);text-decoration:none;font-size:12px;font-weight:600}.dvt-download:hover{background:var(--dsw-alias-button-primary-hover)}.dvt-download:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.dvt-artifact>.dvt-muted{padding:0 10px 10px}.dvt-diff-score>div{height:5px;border-radius:99px;background:var(--dsw-alias-border-l2);overflow:hidden}.dvt-diff-score i{display:block;height:100%;min-width:2px;background:linear-gradient(90deg,var(--dsw-alias-state-warn-primary),var(--dsw-alias-state-error-primary));border-radius:99px}.dvt-tool h4{font-size:11px;margin:0 0 6px}.dvt-palette{display:grid;grid-template-columns:repeat(auto-fit,minmax(112px,1fr));gap:7px}.dvt-palette>div{display:flex;align-items:center;gap:8px;padding:7px;border:1px solid var(--dsw-alias-border-l1);border-radius:9px}.dvt-palette i{width:28px;height:28px;border-radius:7px;box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2)}.dvt-palette span{display:grid}.dvt-palette strong{font-size:11px}.dvt-palette small{font-size:10px;color:var(--dsw-alias-label-secondary)}
|
|
1372
|
-
.dvt-tutorial-link{margin:0;font-size:12px;line-height:1.5}.dvt-tutorial-link a{color:var(--dsw-alias-state-business-primary);text-decoration:none;font-weight:600}.dvt-tutorial-link a:hover{text-decoration:underline}.dvt-manual-update{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2)}.dvt-manual-update code{flex:1;min-width:0;overflow:auto;white-space:nowrap;font-size:11px;color:var(--dsw-alias-label-primary)}.dvt-settings{display:
|
|
1522
|
+
.dvt-tutorial-link{margin:0;font-size:12px;line-height:1.5}.dvt-tutorial-link a{color:var(--dsw-alias-state-business-primary);text-decoration:none;font-weight:600}.dvt-tutorial-link a:hover{text-decoration:underline}.dvt-manual-update{display:flex;align-items:center;gap:8px;padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2)}.dvt-manual-update code{flex:1;min-width:0;overflow:auto;white-space:nowrap;font-size:11px;color:var(--dsw-alias-label-primary)}.dvt-settings{display:flex;flex-direction:column;width:100%;max-width:900px;min-width:0;box-sizing:border-box;gap:14px;padding:8px 2px 32px;color:var(--dsw-alias-label-primary)}.dvt-settings-footer{display:flex;justify-content:space-between;gap:20px;align-items:flex-start;padding:8px 2px}.dvt-settings-footer h2{font-size:25px;letter-spacing:-.025em;margin:3px 0 6px}.dvt-settings-footer p{max-width:620px;margin:0;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.55}.dvt-kicker{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--dsw-alias-state-business-primary);font-weight:700}.dvt-release{display:grid;gap:4px;min-width:170px;padding:9px 11px;border-radius:10px;background:var(--dsw-alias-bg-layer-2);font-size:10px;color:var(--dsw-alias-label-secondary)}.dvt-release span{display:flex;justify-content:space-between;gap:12px}.dvt-release strong{color:var(--dsw-alias-label-primary)}.dvt-alert{padding:10px 12px;border-radius:10px;font-size:12px;line-height:1.5;display:grid;gap:3px}.dvt-alert.notice{background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 10%,transparent);color:var(--dsw-alias-state-business-primary)}.dvt-alert.warning{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}.dvt-alert.error{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}.dvt-alert.success{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 10%,transparent);color:var(--dsw-alias-state-success-primary)}.dvt-panel{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:15px;border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-shadow-lv1)}.dvt-panel-title{display:flex;align-items:flex-start;justify-content:space-between;flex-wrap:wrap;gap:12px}.dvt-panel-title>div:first-child{flex:1 1 320px;min-width:0}.dvt-panel-title>.dvt-actions{margin-left:auto;justify-content:flex-end}.dvt-panel-title h3{font-size:14px;margin:0}.dvt-panel-title p{font-size:11px;line-height:1.45;color:var(--dsw-alias-label-secondary);margin:4px 0 0;max-width:620px}.dvt-badge{font-size:10px;padding:3px 7px;border-radius:999px;font-weight:650}.dvt-badge.ok{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}.dvt-badge.warning{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}.dvt-badge.error{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 10%,transparent);color:var(--dsw-alias-state-error-primary)}.dvt-form-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.dvt-field{display:grid;min-width:0;gap:6px;align-content:start}.dvt-field>span{font-size:11px;font-weight:600}.dvt-field>small{font-size:10px;color:var(--dsw-alias-label-secondary);line-height:1.4}.dvt-field select,.dvt-field textarea{width:100%;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:8px 10px}.dvt-field select{height:36px}.dvt-field textarea{resize:vertical;min-height:76px}.dvt-check{display:grid;gap:6px;cursor:pointer}.dvt-check input{width:auto}.dvt-check>span{font-size:12px;font-weight:600}.dvt-check>small{font-size:10px;color:var(--dsw-alias-label-secondary);line-height:1.4}.dvt-runtime-facts{display:grid;gap:4px;padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);overflow:auto}.dvt-runtime-facts code{font-size:10px;white-space:nowrap;color:var(--dsw-alias-label-secondary)}.dvt-update-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}.dvt-update-grid>div{display:grid;gap:3px;padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2)}.dvt-update-grid span{font-size:9px;text-transform:uppercase;letter-spacing:.04em;color:var(--dsw-alias-label-caption)}.dvt-update-grid strong{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1373
1523
|
.dvt-settings-footer{margin-top:8px;padding:20px 2px 4px;border-top:1px solid var(--dsw-alias-border-l1);opacity:.82}.dvt-settings-footer h2{font-size:18px;letter-spacing:-.015em;margin:3px 0 5px}.dvt-settings-footer p{font-size:11px;line-height:1.5}.dvt-release{min-width:220px}.dvt-release span{white-space:nowrap}.dvt-essential{border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 30%,var(--dsw-alias-border-l1));box-shadow:var(--dsw-shadow-lv1),0 0 0 3px color-mix(in srgb,var(--dsw-alias-state-business-primary) 5%,transparent)}.dvt-advanced{border:1px solid var(--dsw-alias-border-l1);border-radius:14px;background:var(--dsw-alias-bg-layer-1);overflow:hidden}.dvt-advanced>summary{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:14px 15px;cursor:pointer;list-style:none}.dvt-advanced>summary::-webkit-details-marker{display:none}.dvt-advanced>summary>span:first-child{display:grid;gap:3px}.dvt-advanced>summary strong{font-size:13px}.dvt-advanced>summary small{font-size:10px;line-height:1.45;color:var(--dsw-alias-label-secondary);font-weight:400}.dvt-details-chevron{font-size:15px;opacity:.55;transition:transform .16s ease}.dvt-advanced[open] .dvt-details-chevron{transform:rotate(180deg)}.dvt-advanced-body{display:grid;grid-template-columns:minmax(0,1fr);gap:12px;padding:0 12px 12px}.dvt-advanced-body>.dvt-panel{box-shadow:none}
|
|
1374
1524
|
.dvt-health-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.dvt-health-grid>div{padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);border-left:3px solid var(--dsw-alias-border-l4)}.dvt-health-grid>div[data-status=ok]{border-left-color:var(--dsw-alias-state-success-primary)}.dvt-health-grid>div[data-status=warning],.dvt-health-grid>div[data-status=not_tested]{border-left-color:var(--dsw-alias-state-warn-primary)}.dvt-health-grid>div[data-status=error]{border-left-color:var(--dsw-alias-state-error-primary)}.dvt-health-grid span{font-size:10px;text-transform:capitalize}.dvt-health-grid strong{float:right;font-size:9px;text-transform:uppercase;color:var(--dsw-alias-label-secondary)}.dvt-health-test-tag{display:inline-flex;margin-left:6px;padding:1px 6px;border-radius:999px;background:var(--dsw-alias-bg-layer-1);font-size:9px;font-style:normal;font-weight:600;color:var(--dsw-alias-label-secondary)}.dvt-health-test-tag[data-status=ok]{background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 12%,transparent);color:var(--dsw-alias-state-success-primary)}.dvt-health-test-tag[data-status=warning]{background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 12%,transparent);color:var(--dsw-alias-state-warn-label)}.dvt-health-test-tag[data-status=error]{background:color-mix(in srgb,var(--dsw-alias-state-error-primary) 12%,transparent);color:var(--dsw-alias-state-error-primary)}.dvt-health-grid p{clear:both;margin:5px 0 0;font-size:10px;line-height:1.4;color:var(--dsw-alias-label-secondary)}.dvt-loading{padding:24px;border-radius:12px;background:var(--dsw-alias-bg-layer-2);font-size:12px;color:var(--dsw-alias-label-secondary)}
|
|
1375
1525
|
.dvt-paste-dock{box-sizing:border-box;width:calc(100% - 32px);max-width:var(--dsh-composer-card-max-width,960px);margin:0 auto;display:flex;flex-wrap:wrap;gap:6px;padding:0 2px 6px}.dvt-paste-chip{max-width:100%;height:32px;box-sizing:border-box;display:flex;align-items:center;gap:7px;padding:0 6px 0 10px;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-specific-tip);font-size:12px}.dvt-paste-chip[data-status=copying]{border-color:var(--dsw-alias-state-business-primary)}.dvt-paste-chip[data-status=error]{border-color:var(--dsw-alias-state-error-primary)}.dvt-paste-name{max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvt-paste-detail{color:var(--dsw-alias-label-caption);max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dvt-paste-chip[data-status=error] .dvt-paste-detail{color:var(--dsw-alias-state-error-primary)}.dvt-paste-chip button{width:20px;height:20px;display:grid;place-items:center;border:0;border-radius:50%;padding:0;background:transparent;color:var(--dsw-alias-label-caption);font:inherit;font-size:16px;cursor:pointer}.dvt-paste-chip button:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.dvt-paste-chip button:disabled{opacity:.4;cursor:default}
|
|
1376
1526
|
.dvt-provider-card{border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:9px 10px;display:grid;gap:8px;background:var(--dsw-alias-bg-layer-2)}.dvt-provider-head{display:flex;align-items:center;gap:10px}.dvt-provider-priority{margin-left:auto;font-size:11px;color:var(--dsw-alias-label-secondary);white-space:nowrap}.dvt-provider-actions{display:flex;gap:4px}.dvt-provider-actions button{width:26px;height:26px;display:grid;place-items:center;border:1px solid var(--dsw-alias-border-l1);border-radius:7px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);cursor:pointer;font-size:14px;line-height:1}.dvt-provider-actions button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dvt-provider-actions button:disabled{opacity:.35;cursor:default}.dvt-provider-select{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.dvt-provider-select select{flex:1;min-width:180px;height:36px;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;padding:0 10px}.dvt-provider-tests{display:flex;align-items:center;gap:7px;flex-wrap:wrap}.dvt-provider-test-result{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:8px}.dvt-provider-test-result>div{padding:9px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-2);border-left:3px solid var(--dsw-alias-border-l4)}.dvt-provider-test-result>div[data-status=ok]{border-left-color:var(--dsw-alias-state-success-primary)}.dvt-provider-test-result>div[data-status=warning],.dvt-provider-test-result>div[data-status=not_tested]{border-left-color:var(--dsw-alias-state-warn-primary)}.dvt-provider-test-result>div[data-status=error]{border-left-color:var(--dsw-alias-state-error-primary)}.dvt-provider-test-result span{font-size:10px;text-transform:capitalize}.dvt-provider-test-result strong{float:right;font-size:9px;text-transform:uppercase;color:var(--dsw-alias-label-secondary)}.dvt-provider-test-result p{clear:both;margin:5px 0 0;font-size:10px;line-height:1.4;color:var(--dsw-alias-label-secondary)}.dvt-sorter{display:grid;gap:6px}.dvt-sorter-row{display:flex;align-items:center;gap:10px;padding:6px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2)}.dvt-sorter-index{flex:none;width:24px;height:24px;display:grid;place-items:center;border-radius:6px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,transparent);color:var(--dsw-alias-state-business-primary);font-size:11px;font-weight:700}.dvt-sorter-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}
|
|
1527
|
+
.dvt-save-dock{position:sticky;top:8px;align-self:flex-end;z-index:50;display:flex;align-items:center;gap:10px;max-width:calc(100% - 16px);padding:11px 14px;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-bg-layer-1);box-shadow:var(--dsw-shadow-lv1)}.dvt-save-dock[data-dirty]{border-color:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 45%,var(--dsw-alias-border-l1))}.dvt-save-dock-text{font-size:12px;color:var(--dsw-alias-label-secondary)}.dvt-save-dock[data-dirty] .dvt-save-dock-text{color:var(--dsw-alias-state-warn-label);font-weight:600}.dvt-save-dock-reload{flex:none;display:grid;place-items:center;width:26px;height:26px;border:1px solid transparent;border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;padding:0}.dvt-save-dock-reload:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.dvt-save-dock-reload:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:1px}.dvt-save-dock-reload:disabled{opacity:.4;cursor:default}
|
|
1377
1528
|
@media(max-width:720px){.dvt-settings-footer{display:grid}.dvt-release{width:auto}.dvt-form-grid,.dvt-update-grid{grid-template-columns:1fr}.dvt-metrics{grid-template-columns:1fr}.dvt-artifact-meta{align-items:flex-start;flex-direction:column}.dvt-panel-title{flex-direction:column}}
|
|
1378
1529
|
`;
|
|
1379
1530
|
function installStyles() {
|