@ouraihub/aether-ui 0.1.0 → 0.1.2
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/package.json +3 -3
- package/src/chat/ApprovalCard.svelte +8 -2
- package/src/chat/ChatComposer.svelte +319 -0
- package/src/chat/ChatMessage.svelte +262 -0
- package/src/chat/ChatPanel.css +386 -0
- package/src/chat/ChatPanel.svelte +276 -1880
- package/src/chat/ChatPanelApprovals.svelte +28 -0
- package/src/chat/ChatPanelComposer.svelte +336 -0
- package/src/chat/ChatPanelDialogs.svelte +242 -0
- package/src/chat/ChatPanelHeader.svelte +108 -0
- package/src/chat/ChatPanelMessages.svelte +166 -0
- package/src/chat/ChatPanelMode.svelte +190 -0
- package/src/chat/ChatPanelState.svelte.ts +1 -0
- package/src/chat/ChatPanelToolbar.svelte +436 -0
- package/src/chat/ChatSurface.svelte +168 -0
- package/src/chat/ContextUsageStatus.svelte +97 -0
- package/src/chat/MessageItem.svelte +111 -214
- package/src/chat/ModelEffortPicker.svelte +326 -0
- package/src/chat/PickerEffort.svelte +71 -0
- package/src/chat/ReasoningControl.svelte +184 -0
- package/src/chat/ReasoningSlider.svelte +174 -0
- package/src/chat/SkillPicker.svelte +14 -6
- package/src/chat/UsageControl.svelte +223 -0
- package/src/chat/UsageDetails.svelte +44 -90
- package/src/chat/chat-attachments.svelte.ts +78 -0
- package/src/chat/chat-panel-history.svelte.ts +430 -0
- package/src/chat/chat-panel-models.svelte.ts +97 -0
- package/src/chat/chat-panel-props.ts +38 -0
- package/src/chat/context-status.ts +101 -0
- package/src/chat/icons/LICENSE-REMIX +186 -0
- package/src/chat/icons/LICENSE-SIMPLE-ICONS +30 -0
- package/src/chat/icons/PathIcon.svelte +8 -0
- package/src/chat/icons/effort-icons.ts +65 -0
- package/src/chat/icons/status-icons.ts +105 -0
- package/src/chat/index.ts +25 -1
- package/src/chat/model-effort.ts +177 -0
- package/src/chat/run-session-history.ts +56 -0
- package/src/chat/run-session-types.ts +69 -0
- package/src/chat/run-session.svelte.ts +73 -135
- package/src/chat/test-support/chat-fixture.ts +194 -0
- package/src/chat/test-support/conversation-fixtures.ts +32 -0
- package/src/chat/test-support/run-session-fixture.ts +112 -0
- package/src/dev/Demo.svelte +3 -1
- package/src/i18n/en-chat.d.ts +1 -0
- package/src/i18n/en-chat.js +201 -0
- package/src/i18n/en.ts +58 -180
- package/src/i18n/index.ts +7 -2
- package/src/i18n/zh-CN-chat.d.ts +1 -0
- package/src/i18n/zh-CN-chat.js +190 -0
- package/src/i18n/zh-CN.ts +8 -153
- package/src/logs/LogPanel.svelte +9 -3
- package/src/logs/LogSettings.svelte +3 -1
- package/src/mcp/McpClientEditor.svelte +204 -0
- package/src/mcp/McpClientSettings.svelte +57 -130
- package/src/mcp/McpServerSettings.svelte +47 -11
- package/src/mcp/input.ts +2 -1
- package/src/ports/contract.ts +11 -2
- package/src/ports/fake-optional.ts +81 -0
- package/src/ports/fake.ts +90 -86
- package/src/ports/search.ts +11 -2
- package/src/ports/test-support/fake-fixture.ts +63 -0
- package/src/providers/EndpointKeysDialog.svelte +27 -13
- package/src/providers/EndpointModels.svelte +311 -0
- package/src/providers/EndpointPanel.svelte +33 -258
- package/src/providers/ModelPickerDialog.svelte +59 -16
- package/src/providers/ModelPricing.svelte +125 -0
- package/src/providers/ModelSelect.svelte +22 -8
- package/src/providers/ModelSettingsDialog.svelte +61 -126
- package/src/providers/ProviderDialogs.svelte +120 -0
- package/src/providers/ProviderList.svelte +159 -0
- package/src/providers/ProvidersSettings.svelte +67 -207
- package/src/providers/RequestConfigDialog.svelte +40 -12
- package/src/providers/SecretInput.svelte +11 -3
- package/src/providers/draft.ts +39 -13
- package/src/providers/edit-session.ts +31 -7
- package/src/providers/reasoning.ts +18 -4
- package/src/providers/revision.svelte.ts +3 -1
- package/src/providers/test-support/providers-fixture.ts +120 -0
- package/src/search/SearchAdvancedTools.svelte +182 -0
- package/src/search/SearchProviderCard.svelte +195 -0
- package/src/search/SearchSettings.svelte +62 -265
- package/src/search/settings-flow.ts +8 -3
- package/src/skills/SkillAdd.svelte +51 -18
- package/src/skills/SkillAuthoring.svelte +69 -20
- package/src/skills/SkillEditor.svelte +13 -3
- package/src/skills/SkillPreviewDialog.svelte +19 -5
- package/src/skills/SkillsSettings.svelte +11 -4
- package/src/skills/test-support/skills-fixture.ts +139 -0
- package/src/tauri/index.ts +23 -7
- package/src/web/index.ts +90 -25
package/src/i18n/zh-CN.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Messages } from './en'
|
|
2
|
+
import { zhCNChat } from './zh-CN-chat.js'
|
|
2
3
|
|
|
3
4
|
export const zhCN: Messages = {
|
|
5
|
+
...zhCNChat,
|
|
4
6
|
'common.confirm': '确定',
|
|
5
7
|
'common.cancel': '取消',
|
|
6
8
|
'skills.add.title': '添加技能',
|
|
@@ -17,7 +19,8 @@ export const zhCN: Messages = {
|
|
|
17
19
|
'skills.add.system_hint': '扫描用户目录中已知 CLI 技能文件夹,也可选择项目目录进行搜索。',
|
|
18
20
|
'skills.add.rescan': '扫描用户目录',
|
|
19
21
|
'skills.add.pick_search_directory': '选择技能目录',
|
|
20
|
-
'skills.add.local_hint':
|
|
22
|
+
'skills.add.local_hint':
|
|
23
|
+
'选择 SKILL.md、.zip 技能包或技能目录,包内参考文件和脚本将一并展示以供确认。',
|
|
21
24
|
'skills.add.pick_directory': '选择目录',
|
|
22
25
|
'skills.add.model': '模型',
|
|
23
26
|
'skills.add.choose_model': '请先选择已配置的对话模型再发送',
|
|
@@ -34,139 +37,6 @@ export const zhCN: Messages = {
|
|
|
34
37
|
'skills.add.working': '处理中…',
|
|
35
38
|
'skills.add.no_results': '未找到技能。',
|
|
36
39
|
'skills.add.ignored': '未导入文件',
|
|
37
|
-
'chat.networkOn': '联网搜索已开启 · 点击关闭',
|
|
38
|
-
'chat.networkOff': '联网搜索已关闭 · 点击开启',
|
|
39
|
-
'chat.title': '对话',
|
|
40
|
-
'chat.history': '会话',
|
|
41
|
-
'chat.historyFailed': '读取会话失败',
|
|
42
|
-
'chat.newConversation': '新对话',
|
|
43
|
-
'chat.close': '关闭',
|
|
44
|
-
'chat.messages': '消息',
|
|
45
|
-
'chat.input': '消息',
|
|
46
|
-
'chat.placeholder': '输入消息,Ctrl/Cmd+Enter 发送',
|
|
47
|
-
'chat.send': '发送',
|
|
48
|
-
'chat.stop': '停止',
|
|
49
|
-
'chat.regenerate': '重新生成',
|
|
50
|
-
'chat.stopped': '已停止',
|
|
51
|
-
'chat.interrupted': '已中断:回复过程中应用被关闭',
|
|
52
|
-
'chat.exhausted': '已达到工具调用轮数上限',
|
|
53
|
-
'chat.copy': '复制',
|
|
54
|
-
'chat.copied': '已复制',
|
|
55
|
-
'chat.copyFailed': '复制失败',
|
|
56
|
-
'chat.insert': '插入',
|
|
57
|
-
'chat.retry': '重试',
|
|
58
|
-
'chat.more': '更多操作',
|
|
59
|
-
'chat.translationReply': '译文',
|
|
60
|
-
'chat.noSourceModel': '来源模型未知',
|
|
61
|
-
'chat.switchModel': '切换模型',
|
|
62
|
-
'chat.translate': '翻译',
|
|
63
|
-
'chat.editReply': '编辑',
|
|
64
|
-
'chat.replyText': '回复 Markdown',
|
|
65
|
-
'chat.replyModel': '回复模型',
|
|
66
|
-
'chat.targetLanguage': '目标语言',
|
|
67
|
-
'chat.branch': '分支',
|
|
68
|
-
'chat.copyConversation': '复制为新对话',
|
|
69
|
-
'chat.save': '保存',
|
|
70
|
-
'chat.saveFile': '保存到本地文件',
|
|
71
|
-
'chat.export': '导出',
|
|
72
|
-
'chat.exportMarkdown': '导出为 Markdown',
|
|
73
|
-
'chat.exportFailed': '下载 Markdown 失败',
|
|
74
|
-
'chat.saveNote': '保存到笔记',
|
|
75
|
-
'chat.saveNoteFailed': '保存笔记失败',
|
|
76
|
-
'chat.useContext': '设置为上下文',
|
|
77
|
-
'chat.deleteReply': '删除',
|
|
78
|
-
'chat.deleteReplyTitle': '确定要删除此消息吗?',
|
|
79
|
-
'chat.deleteReparentBody': '后续对话会接到上一条回复上。此操作无法撤销。',
|
|
80
|
-
'chat.sourceModelUnavailable': '来源模型已不可用,请点 @ 选择其他模型。',
|
|
81
|
-
'chat.candidateHint': '原回复将保留。点 👍 设置为上下文后,可从候选回复继续对话。',
|
|
82
|
-
'chat.editReplyHint': '编辑只替换此回复。若回复被同时修改,将拒绝保存并保留你的草稿。',
|
|
83
|
-
'chat.replyRefreshFailed': '重新加载已保存回复失败。',
|
|
84
|
-
'chat.delete': '删除对话',
|
|
85
|
-
'chat.network': '联网搜索',
|
|
86
|
-
'chat.sources': '来源',
|
|
87
|
-
'chat.networkPrivacy': '外部搜索只发送本轮问题;原生搜索优先时,可能向模型服务商发送会话及附带笔记上下文。',
|
|
88
|
-
'chat.searching': '正在搜索网页…',
|
|
89
|
-
'chat.searchResults': '找到 {count} 条结果',
|
|
90
|
-
'chat.reasoning': '思考',
|
|
91
|
-
'chat.reasoningEffort': '思考强度',
|
|
92
|
-
'chat.reasoningStrength': '强度',
|
|
93
|
-
'chat.reasoningFaster': '更快',
|
|
94
|
-
'chat.reasoningSmarter': '更智能',
|
|
95
|
-
'chat.resetReasoning': '恢复默认',
|
|
96
|
-
'chat.reasoningDefaultHint': '默认不发送思考参数,由服务商决定。选择档位可指定强度。',
|
|
97
|
-
'chat.reasoningUnconfigured': '此模型尚未配置思考能力。在模型设置中打开“推理”能力并选择支持的档位后,即可使用滑块。',
|
|
98
|
-
'chat.unknown': '未知',
|
|
99
|
-
'chat.contextUsage': '上下文用量',
|
|
100
|
-
'chat.usage': 'Token 用量',
|
|
101
|
-
'chat.reported': '实测',
|
|
102
|
-
'chat.estimated': '估算',
|
|
103
|
-
'chat.modelsFailed': '无法加载模型能力',
|
|
104
|
-
'chat.modelsLoading': '正在加载模型…',
|
|
105
|
-
'chat.retryModels': '重新加载模型',
|
|
106
|
-
'chat.historyLoading': '正在加载会话…',
|
|
107
|
-
'chat.retryHistory': '重试会话操作',
|
|
108
|
-
'chat.rename': '重命名对话',
|
|
109
|
-
'chat.conversationTitle': '对话标题',
|
|
110
|
-
'chat.expandInput': '展开输入框',
|
|
111
|
-
'chat.collapseInput': '收起输入框',
|
|
112
|
-
'chat.backToBottom': '回到底部',
|
|
113
|
-
'chat.draftRecoverable': '未发送的消息已保留,清空当前草稿后可恢复。',
|
|
114
|
-
'chat.restoreDraft': '恢复未发送消息',
|
|
115
|
-
'chat.tools': '更多工具',
|
|
116
|
-
'chat.uploadAttachment': '上传附件',
|
|
117
|
-
'chat.generateImage': '生成图片',
|
|
118
|
-
'chat.generateImageOff': '关闭生成图片',
|
|
119
|
-
'chat.quickPanel': '输入快捷面板',
|
|
120
|
-
'chat.toolbarCustomize': '自定义工具栏',
|
|
121
|
-
'chat.toolbarRestore': '恢复默认',
|
|
122
|
-
'chat.toolbarDrag': '拖动或按 ↑/↓ 调整 {name} 的顺序',
|
|
123
|
-
'chat.paintingUnconfigured': '请先在设置中选择绘图模型',
|
|
124
|
-
'chat.toolsUnsupported': '当前模型不支持工具',
|
|
125
|
-
'chat.generatedImages': '生成的图片',
|
|
126
|
-
'chat.openGeneratedImage': '打开生成的第 {index} 张图片',
|
|
127
|
-
'chat.removeImage': '移除第 {index} 张图片',
|
|
128
|
-
'chat.openImage': '打开第 {index} 张图片',
|
|
129
|
-
'chat.imageExpired': '图片已过期',
|
|
130
|
-
'chat.visionUnsupported': '当前模型不支持图片',
|
|
131
|
-
'chat.imageLimit': '每条消息最多 {max} 张图片',
|
|
132
|
-
'chat.imageType': '仅支持 PNG、JPEG、WebP 和 GIF 图片',
|
|
133
|
-
'chat.imageSize': '单张图片不能超过 4 MiB',
|
|
134
|
-
'chat.currentUsage': '本轮',
|
|
135
|
-
'chat.totalUsage': '会话已知累计',
|
|
136
|
-
'chat.usage.inputTokens': '输入',
|
|
137
|
-
'chat.usage.outputTokens': '输出',
|
|
138
|
-
'chat.usage.cacheReadTokens': '缓存读取',
|
|
139
|
-
'chat.usage.cacheWriteTokens': '缓存写入',
|
|
140
|
-
'chat.usage.reasoningTokens': '思考 tokens',
|
|
141
|
-
'chat.usageHint': '缓存计入输入,思考计入输出;未知数量不当作零。',
|
|
142
|
-
'chat.cost': '费用',
|
|
143
|
-
'chat.effort.default': '默认',
|
|
144
|
-
'chat.effort.none': '关闭',
|
|
145
|
-
'chat.effort.auto': '自动',
|
|
146
|
-
'chat.effort.minimal': '最低',
|
|
147
|
-
'chat.effort.low': '低',
|
|
148
|
-
'chat.effort.medium': '中',
|
|
149
|
-
'chat.effort.high': '高',
|
|
150
|
-
'chat.effort.xhigh': '很高',
|
|
151
|
-
'chat.effort.max': '最大',
|
|
152
|
-
'chat.mode.label': '权限模式',
|
|
153
|
-
'chat.mode.default': '逐次确认',
|
|
154
|
-
'chat.mode.defaultHint': '按工具设置逐次确认。',
|
|
155
|
-
'chat.mode.plan': '仅规划',
|
|
156
|
-
'chat.mode.planHint': '只读与规划,不执行改动。',
|
|
157
|
-
'chat.mode.accept_edits': '自动接受编辑',
|
|
158
|
-
'chat.mode.accept_editsHint': '自动批准编辑,其他操作按规则确认。',
|
|
159
|
-
'chat.mode.auto': '智能批准',
|
|
160
|
-
'chat.mode.autoHint': '自动批准应用工具,规则可要求确认。',
|
|
161
|
-
'chat.mode.full_access': '完全访问',
|
|
162
|
-
'chat.mode.full_accessHint': '本次运行免确认,禁用工具除外。',
|
|
163
|
-
'chat.mode.planBadge': '仅规划',
|
|
164
|
-
'chat.mode.fullAccessTitle': '本次运行允许完全访问?',
|
|
165
|
-
'chat.mode.fullAccessBody': '仅本次运行,工具可不经确认改动数据和执行命令;已禁止的工具仍不执行。此选择不会保存。',
|
|
166
|
-
'chat.mode.ruleNotice': '规则检查可能漏判,不是安全沙箱;MCP 工具保留各自审批设置。',
|
|
167
|
-
'chat.mode.navigate': '选择',
|
|
168
|
-
'chat.mode.confirm': '确认',
|
|
169
|
-
'chat.mode.close': '关闭',
|
|
170
40
|
'providers.max_output': '最大输出(tokens)',
|
|
171
41
|
'search.search': '网页搜索',
|
|
172
42
|
'search.fetch': '读取网页',
|
|
@@ -198,8 +68,6 @@ export const zhCN: Messages = {
|
|
|
198
68
|
'search.pageUrl': 'URL',
|
|
199
69
|
'search.password': '密码',
|
|
200
70
|
'search.read': '读取',
|
|
201
|
-
'chat.deleteTitle': '删除这个对话?',
|
|
202
|
-
'chat.deleteBody': '删除后消息无法恢复。',
|
|
203
71
|
'search.manageKeys': '管理密钥',
|
|
204
72
|
'search.newKey': '新密钥',
|
|
205
73
|
'search.addKey': '添加密钥',
|
|
@@ -218,21 +86,6 @@ export const zhCN: Messages = {
|
|
|
218
86
|
'search.nativePrivacy':
|
|
219
87
|
'已声明能力的兼容模型可使用原生搜索,其余使用选定的外部服务商。原生搜索可能将会话和笔记上下文发送给模型服务商;本地黑名单和截断不控制供应商原生搜索。',
|
|
220
88
|
'providers.nativeWebSearch': '模型支持原生联网搜索',
|
|
221
|
-
'chat.deleteFailed': '删除对话失败',
|
|
222
|
-
'chat.empty': '输入问题开始对话',
|
|
223
|
-
'chat.noModels': '还没有对话模型,请先添加服务商和模型。',
|
|
224
|
-
'chat.openSettings': '打开设置',
|
|
225
|
-
'chat.context.remove': '下一条消息不附带 {label}',
|
|
226
|
-
'chat.tool.calling': '正在调用 {name}',
|
|
227
|
-
'chat.tool.ok': '{name}:{summary}',
|
|
228
|
-
'chat.tool.error': '{name} 失败:{summary}',
|
|
229
|
-
'chat.tool.denied': '{name}:已拒绝',
|
|
230
|
-
'chat.tool.unknown': '{name}:结果未知,可能已执行',
|
|
231
|
-
'chat.approval.title': '允许调用 {name}?',
|
|
232
|
-
'chat.approval.host': '应用工具',
|
|
233
|
-
'chat.approval.mcp': 'MCP 服务 {server}',
|
|
234
|
-
'chat.approval.allow': '允许本次',
|
|
235
|
-
'chat.approval.deny': '拒绝',
|
|
236
89
|
'logs.title': '日志',
|
|
237
90
|
'logs.problemsOnly': '只看问题',
|
|
238
91
|
'logs.openDir': '打开目录',
|
|
@@ -376,7 +229,8 @@ export const zhCN: Messages = {
|
|
|
376
229
|
'providers.error.reasoning.protocol_mismatch': '思考协议与线路协议不匹配',
|
|
377
230
|
'providers.error.reasoning.invalid_budget': '预算至少 1024,且必须小于最大输出(默认 4096)',
|
|
378
231
|
'providers.error.reasoning.unexpected_budget': '此思考协议不使用预算',
|
|
379
|
-
'providers.error.pricing.invalid':
|
|
232
|
+
'providers.error.pricing.invalid':
|
|
233
|
+
'价格须为 0 到 1000000 之间的数字,首档从 0 开始且起点递增,最多 8 档',
|
|
380
234
|
'providers.probe.missing_key': '需要密钥',
|
|
381
235
|
'providers.probe.unauthorized': '认证失败',
|
|
382
236
|
'providers.probe.not_found': '找不到模型列表(404)',
|
|
@@ -425,7 +279,8 @@ export const zhCN: Messages = {
|
|
|
425
279
|
'providers.headers_too_many': '最多 20 个请求头',
|
|
426
280
|
'providers.check': '检测',
|
|
427
281
|
'providers.check_ok': '连接正常 · 可用 {count} 个模型',
|
|
428
|
-
'providers.suggest_protocol':
|
|
282
|
+
'providers.suggest_protocol':
|
|
283
|
+
'这条线路支持 Anthropic 原生协议(Messages),Claude 模型的图片和思考走原生格式更稳定',
|
|
429
284
|
'providers.suggest_protocol_apply': '改用 Anthropic 协议',
|
|
430
285
|
'providers.sync_models': '同步模型',
|
|
431
286
|
'providers.add_model_manual': '添加模型',
|
package/src/logs/LogPanel.svelte
CHANGED
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
let entries = $state<LogEntry[]>([])
|
|
19
19
|
let failed = $state(false)
|
|
20
20
|
let problemsOnly = $state(false)
|
|
21
|
-
const shown = $derived(
|
|
21
|
+
const shown = $derived(
|
|
22
|
+
problemsOnly ? entries.filter((e) => e.level === 'ERROR' || e.level === 'WARN') : entries,
|
|
23
|
+
)
|
|
22
24
|
|
|
23
25
|
async function refresh() {
|
|
24
26
|
if (!logs) return
|
|
@@ -66,11 +68,15 @@
|
|
|
66
68
|
{t('logs.problemsOnly')}
|
|
67
69
|
</label>
|
|
68
70
|
{#if ports.desktop}
|
|
69
|
-
<Button variant="outline" size="sm" onclick={() => void openDir()}
|
|
71
|
+
<Button variant="outline" size="sm" onclick={() => void openDir()}
|
|
72
|
+
>{t('logs.openDir')}</Button
|
|
73
|
+
>
|
|
70
74
|
{/if}
|
|
71
75
|
</header>
|
|
72
76
|
{#if failed}
|
|
73
|
-
<Alert variant="destructive"
|
|
77
|
+
<Alert variant="destructive"
|
|
78
|
+
><AlertDescription>{t('logs.loadFailed')}</AlertDescription></Alert
|
|
79
|
+
>
|
|
74
80
|
{/if}
|
|
75
81
|
{#if shown.length === 0}
|
|
76
82
|
<Empty.Root>
|
|
@@ -50,7 +50,9 @@
|
|
|
50
50
|
<Field.Description>{t('logs.levelHint')}</Field.Description>
|
|
51
51
|
</Field.Field>
|
|
52
52
|
{#if status && !status.available}
|
|
53
|
-
<Alert variant="destructive"
|
|
53
|
+
<Alert variant="destructive"
|
|
54
|
+
><AlertDescription>{t('logs.unavailable')}</AlertDescription></Alert
|
|
55
|
+
>
|
|
54
56
|
{/if}
|
|
55
57
|
</Field.Group>
|
|
56
58
|
{/if}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Button } from '#lib/components/ui/button/index.js'
|
|
3
|
+
import * as Dialog from '#lib/components/ui/dialog/index.js'
|
|
4
|
+
import * as Field from '#lib/components/ui/field/index.js'
|
|
5
|
+
import { Input } from '#lib/components/ui/input/index.js'
|
|
6
|
+
import * as Select from '#lib/components/ui/select/index.js'
|
|
7
|
+
import { Switch } from '#lib/components/ui/switch/index.js'
|
|
8
|
+
import { Textarea } from '#lib/components/ui/textarea/index.js'
|
|
9
|
+
import CopyInput from '../CopyInput.svelte'
|
|
10
|
+
import { getKitContext } from '../context'
|
|
11
|
+
import type { McpTransport } from '../ports'
|
|
12
|
+
|
|
13
|
+
let {
|
|
14
|
+
open = $bindable(false),
|
|
15
|
+
editId,
|
|
16
|
+
name = $bindable(''),
|
|
17
|
+
slug = $bindable(''),
|
|
18
|
+
kind = $bindable<McpTransport['kind']>('http'),
|
|
19
|
+
url = $bindable(''),
|
|
20
|
+
command = $bindable(''),
|
|
21
|
+
args = $bindable(''),
|
|
22
|
+
cwd = $bindable(''),
|
|
23
|
+
replaceSecret = $bindable(true),
|
|
24
|
+
headers = $bindable(''),
|
|
25
|
+
query = $bindable(''),
|
|
26
|
+
env = $bindable(''),
|
|
27
|
+
currentKeys = [],
|
|
28
|
+
editorSaving = false,
|
|
29
|
+
busy = false,
|
|
30
|
+
onclose,
|
|
31
|
+
onsave,
|
|
32
|
+
onchangeKind,
|
|
33
|
+
onchangeReplacement,
|
|
34
|
+
oninputRevision,
|
|
35
|
+
onsecretInput,
|
|
36
|
+
}: {
|
|
37
|
+
open?: boolean
|
|
38
|
+
editId: string | null
|
|
39
|
+
name?: string
|
|
40
|
+
slug?: string
|
|
41
|
+
kind?: McpTransport['kind']
|
|
42
|
+
url?: string
|
|
43
|
+
command?: string
|
|
44
|
+
args?: string
|
|
45
|
+
cwd?: string
|
|
46
|
+
replaceSecret?: boolean
|
|
47
|
+
headers?: string
|
|
48
|
+
query?: string
|
|
49
|
+
env?: string
|
|
50
|
+
currentKeys?: string[]
|
|
51
|
+
editorSaving?: boolean
|
|
52
|
+
busy?: boolean
|
|
53
|
+
onclose: () => void
|
|
54
|
+
onsave: () => void
|
|
55
|
+
onchangeKind: (kind: McpTransport['kind']) => void
|
|
56
|
+
onchangeReplacement: (value: boolean) => void
|
|
57
|
+
oninputRevision: () => void
|
|
58
|
+
onsecretInput: () => void
|
|
59
|
+
} = $props()
|
|
60
|
+
|
|
61
|
+
const { t } = getKitContext().i18n
|
|
62
|
+
const KINDS: McpTransport['kind'][] = ['http', 'stdio']
|
|
63
|
+
const ARGS_PLACEHOLDER = '-y\n@modelcontextprotocol/server-filesystem'
|
|
64
|
+
</script>
|
|
65
|
+
|
|
66
|
+
<Dialog.Root
|
|
67
|
+
bind:open
|
|
68
|
+
onOpenChange={(isOpen) => {
|
|
69
|
+
if (!isOpen) onclose()
|
|
70
|
+
}}
|
|
71
|
+
>
|
|
72
|
+
<Dialog.Content class="sm:max-w-xl" oninput={oninputRevision}>
|
|
73
|
+
<Dialog.Header>
|
|
74
|
+
<Dialog.Title>{editId ? t('mcp.client.editTitle') : t('mcp.client.add')}</Dialog.Title>
|
|
75
|
+
</Dialog.Header>
|
|
76
|
+
<Field.Group>
|
|
77
|
+
<div class="flex gap-3">
|
|
78
|
+
<Field.Field class="flex-1">
|
|
79
|
+
<Field.Label for="kit-mcp-name">{t('mcp.client.name')}</Field.Label>
|
|
80
|
+
<Input id="kit-mcp-name" maxlength={200} bind:value={name} />
|
|
81
|
+
</Field.Field>
|
|
82
|
+
<Field.Field class="w-40">
|
|
83
|
+
<Field.Label for="kit-mcp-slug">{t('mcp.client.slug')}</Field.Label>
|
|
84
|
+
<Input id="kit-mcp-slug" class="font-mono" maxlength={24} bind:value={slug} />
|
|
85
|
+
</Field.Field>
|
|
86
|
+
</div>
|
|
87
|
+
<Field.Field>
|
|
88
|
+
<Field.Label for="kit-mcp-transport">{t('mcp.client.transport')}</Field.Label>
|
|
89
|
+
<Select.Root
|
|
90
|
+
type="single"
|
|
91
|
+
value={kind}
|
|
92
|
+
onValueChange={(value) => onchangeKind(value as McpTransport['kind'])}
|
|
93
|
+
>
|
|
94
|
+
<Select.Trigger id="kit-mcp-transport" class="w-full">
|
|
95
|
+
{t(`mcp.client.transport.${kind}`)}
|
|
96
|
+
</Select.Trigger>
|
|
97
|
+
<Select.Content>
|
|
98
|
+
<Select.Group>
|
|
99
|
+
{#each KINDS as option (option)}
|
|
100
|
+
<Select.Item value={option} label={t(`mcp.client.transport.${option}`)} />
|
|
101
|
+
{/each}
|
|
102
|
+
</Select.Group>
|
|
103
|
+
</Select.Content>
|
|
104
|
+
</Select.Root>
|
|
105
|
+
</Field.Field>
|
|
106
|
+
{#if kind === 'http'}
|
|
107
|
+
<Field.Field>
|
|
108
|
+
<Field.Label for="kit-mcp-url">{t('mcp.client.url')}</Field.Label>
|
|
109
|
+
<CopyInput
|
|
110
|
+
id="kit-mcp-url"
|
|
111
|
+
class="font-mono"
|
|
112
|
+
placeholder="https://example.com/mcp"
|
|
113
|
+
bind:value={url}
|
|
114
|
+
/>
|
|
115
|
+
<Field.Description>{t('mcp.client.urlHint')}</Field.Description>
|
|
116
|
+
</Field.Field>
|
|
117
|
+
{:else}
|
|
118
|
+
<Field.Field>
|
|
119
|
+
<Field.Label for="kit-mcp-command">{t('mcp.client.command')}</Field.Label>
|
|
120
|
+
<Input
|
|
121
|
+
id="kit-mcp-command"
|
|
122
|
+
class="font-mono"
|
|
123
|
+
maxlength={1024}
|
|
124
|
+
placeholder="npx"
|
|
125
|
+
bind:value={command}
|
|
126
|
+
/>
|
|
127
|
+
</Field.Field>
|
|
128
|
+
<Field.Field>
|
|
129
|
+
<Field.Label for="kit-mcp-args">{t('mcp.client.args')}</Field.Label>
|
|
130
|
+
<Textarea
|
|
131
|
+
id="kit-mcp-args"
|
|
132
|
+
class="font-mono text-xs"
|
|
133
|
+
placeholder={ARGS_PLACEHOLDER}
|
|
134
|
+
bind:value={args}
|
|
135
|
+
/>
|
|
136
|
+
<Field.Description>{t('mcp.client.argsHint')}</Field.Description>
|
|
137
|
+
</Field.Field>
|
|
138
|
+
<Field.Field>
|
|
139
|
+
<Field.Label for="kit-mcp-cwd">{t('mcp.client.cwd')}</Field.Label>
|
|
140
|
+
<Input id="kit-mcp-cwd" class="font-mono" bind:value={cwd} />
|
|
141
|
+
<Field.Description>{t('mcp.client.cwdHint')}</Field.Description>
|
|
142
|
+
</Field.Field>
|
|
143
|
+
{/if}
|
|
144
|
+
{#if editId}
|
|
145
|
+
<Field.Field orientation="horizontal">
|
|
146
|
+
<Switch
|
|
147
|
+
id="kit-mcp-replace"
|
|
148
|
+
checked={replaceSecret}
|
|
149
|
+
onCheckedChange={onchangeReplacement}
|
|
150
|
+
/>
|
|
151
|
+
<Field.Label for="kit-mcp-replace">
|
|
152
|
+
{t('mcp.client.replaceSecret', { keys: currentKeys.join(', ') || '—' })}
|
|
153
|
+
</Field.Label>
|
|
154
|
+
</Field.Field>
|
|
155
|
+
{/if}
|
|
156
|
+
{#if replaceSecret && kind === 'http'}
|
|
157
|
+
<Field.Field>
|
|
158
|
+
<Field.Label for="kit-mcp-headers">{t('mcp.client.headers')}</Field.Label>
|
|
159
|
+
<Textarea
|
|
160
|
+
id="kit-mcp-headers"
|
|
161
|
+
class="font-mono text-xs"
|
|
162
|
+
placeholder="Authorization: Bearer …"
|
|
163
|
+
bind:value={headers}
|
|
164
|
+
oninput={onsecretInput}
|
|
165
|
+
/>
|
|
166
|
+
</Field.Field>
|
|
167
|
+
<Field.Field>
|
|
168
|
+
<Field.Label for="kit-mcp-query">{t('mcp.client.query')}</Field.Label>
|
|
169
|
+
<Textarea
|
|
170
|
+
id="kit-mcp-query"
|
|
171
|
+
class="font-mono text-xs"
|
|
172
|
+
placeholder="ak=…"
|
|
173
|
+
bind:value={query}
|
|
174
|
+
oninput={onsecretInput}
|
|
175
|
+
/>
|
|
176
|
+
<Field.Description>{t('mcp.client.secretHint')}</Field.Description>
|
|
177
|
+
</Field.Field>
|
|
178
|
+
{:else if replaceSecret}
|
|
179
|
+
<Field.Field>
|
|
180
|
+
<Field.Label for="kit-mcp-env">{t('mcp.client.env')}</Field.Label>
|
|
181
|
+
<Textarea
|
|
182
|
+
id="kit-mcp-env"
|
|
183
|
+
class="font-mono text-xs"
|
|
184
|
+
placeholder="GITHUB_TOKEN=…"
|
|
185
|
+
bind:value={env}
|
|
186
|
+
oninput={onsecretInput}
|
|
187
|
+
/>
|
|
188
|
+
<Field.Description>{t('mcp.client.envHint')}</Field.Description>
|
|
189
|
+
</Field.Field>
|
|
190
|
+
{/if}
|
|
191
|
+
</Field.Group>
|
|
192
|
+
<Dialog.Footer>
|
|
193
|
+
<Button variant="outline" onclick={onclose}>{t('common.cancel')}</Button>
|
|
194
|
+
<Button
|
|
195
|
+
disabled={busy ||
|
|
196
|
+
editorSaving ||
|
|
197
|
+
!name.trim() ||
|
|
198
|
+
!slug.trim() ||
|
|
199
|
+
!(kind === 'http' ? url.trim() : command.trim())}
|
|
200
|
+
onclick={onsave}>{t('mcp.client.save')}</Button
|
|
201
|
+
>
|
|
202
|
+
</Dialog.Footer>
|
|
203
|
+
</Dialog.Content>
|
|
204
|
+
</Dialog.Root>
|