codexmate 0.0.19 → 0.0.21
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.en.md +349 -255
- package/README.md +284 -248
- package/cli/agents-files.js +162 -0
- package/cli/archive-helpers.js +446 -0
- package/cli/auth-profiles.js +359 -0
- package/cli/builtin-proxy.js +580 -0
- package/cli/claude-proxy.js +998 -0
- package/cli/config-bootstrap.js +384 -0
- package/cli/config-health.js +338 -0
- package/cli/openclaw-config.js +629 -0
- package/cli/skills.js +1141 -0
- package/cli/zip-commands.js +510 -0
- package/cli.js +13129 -12973
- package/lib/cli-file-utils.js +151 -151
- package/lib/cli-models-utils.js +419 -152
- package/lib/cli-network-utils.js +164 -148
- package/lib/cli-path-utils.js +69 -0
- package/lib/cli-session-utils.js +121 -121
- package/lib/cli-sessions.js +386 -0
- package/lib/cli-utils.js +155 -155
- package/lib/download-artifacts.js +77 -0
- package/lib/mcp-stdio.js +440 -440
- package/lib/task-orchestrator.js +869 -0
- package/lib/text-diff.js +303 -303
- package/lib/workflow-engine.js +340 -340
- package/package.json +74 -63
- package/res/json5.min.js +1 -1
- package/res/vue.global.prod.js +13 -0
- package/web-ui/app.js +530 -5548
- package/web-ui/index.html +33 -2246
- package/web-ui/logic.agents-diff.mjs +386 -0
- package/web-ui/logic.claude.mjs +168 -0
- package/web-ui/logic.mjs +5 -793
- package/web-ui/logic.runtime.mjs +124 -0
- package/web-ui/logic.sessions.mjs +581 -0
- package/web-ui/modules/api.mjs +90 -0
- package/web-ui/modules/app.computed.dashboard.mjs +113 -0
- package/web-ui/modules/app.computed.index.mjs +15 -0
- package/web-ui/modules/app.computed.main-tabs.mjs +195 -0
- package/web-ui/modules/app.computed.session.mjs +507 -0
- package/web-ui/modules/app.constants.mjs +15 -0
- package/web-ui/modules/app.methods.agents.mjs +493 -0
- package/web-ui/modules/app.methods.claude-config.mjs +174 -0
- package/web-ui/modules/app.methods.codex-config.mjs +640 -0
- package/web-ui/modules/app.methods.index.mjs +88 -0
- package/web-ui/modules/app.methods.install.mjs +149 -0
- package/web-ui/modules/app.methods.navigation.mjs +619 -0
- package/web-ui/modules/app.methods.openclaw-core.mjs +814 -0
- package/web-ui/modules/app.methods.openclaw-editing.mjs +372 -0
- package/web-ui/modules/app.methods.openclaw-persist.mjs +369 -0
- package/web-ui/modules/app.methods.providers.mjs +363 -0
- package/web-ui/modules/app.methods.runtime.mjs +323 -0
- package/web-ui/modules/app.methods.session-actions.mjs +520 -0
- package/web-ui/modules/app.methods.session-browser.mjs +626 -0
- package/web-ui/modules/app.methods.session-timeline.mjs +448 -0
- package/web-ui/modules/app.methods.session-trash.mjs +422 -0
- package/web-ui/modules/app.methods.startup-claude.mjs +412 -0
- package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
- package/web-ui/modules/config-mode.computed.mjs +126 -124
- package/web-ui/modules/skills.computed.mjs +107 -107
- package/web-ui/modules/skills.methods.mjs +481 -481
- package/web-ui/partials/index/layout-footer.html +13 -0
- package/web-ui/partials/index/layout-header.html +402 -0
- package/web-ui/partials/index/modal-config-template-agents.html +125 -0
- package/web-ui/partials/index/modal-confirm-toast.html +32 -0
- package/web-ui/partials/index/modal-health-check.html +72 -0
- package/web-ui/partials/index/modal-openclaw-config.html +280 -0
- package/web-ui/partials/index/modal-skills.html +184 -0
- package/web-ui/partials/index/modals-basic.html +156 -0
- package/web-ui/partials/index/panel-config-claude.html +126 -0
- package/web-ui/partials/index/panel-config-codex.html +237 -0
- package/web-ui/partials/index/panel-config-openclaw.html +78 -0
- package/web-ui/partials/index/panel-docs.html +130 -0
- package/web-ui/partials/index/panel-market.html +174 -0
- package/web-ui/partials/index/panel-orchestration.html +397 -0
- package/web-ui/partials/index/panel-sessions.html +292 -0
- package/web-ui/partials/index/panel-settings.html +190 -0
- package/web-ui/partials/index/panel-usage.html +213 -0
- package/web-ui/session-helpers.mjs +559 -362
- package/web-ui/source-bundle.cjs +233 -0
- package/web-ui/styles/base-theme.css +271 -0
- package/web-ui/styles/controls-forms.css +360 -0
- package/web-ui/styles/docs-panel.css +182 -0
- package/web-ui/styles/feedback.css +108 -0
- package/web-ui/styles/health-check-dialog.css +144 -0
- package/web-ui/styles/layout-shell.css +376 -0
- package/web-ui/styles/modals-core.css +464 -0
- package/web-ui/styles/navigation-panels.css +348 -0
- package/web-ui/styles/openclaw-structured.css +266 -0
- package/web-ui/styles/responsive.css +450 -0
- package/web-ui/styles/sessions-list.css +400 -0
- package/web-ui/styles/sessions-preview.css +411 -0
- package/web-ui/styles/sessions-toolbar-trash.css +243 -0
- package/web-ui/styles/sessions-usage.css +628 -0
- package/web-ui/styles/skills-list.css +296 -0
- package/web-ui/styles/skills-market.css +335 -0
- package/web-ui/styles/task-orchestration.css +776 -0
- package/web-ui/styles/titles-cards.css +408 -0
- package/web-ui/styles.css +18 -4668
- package/web-ui.html +17 -17
- package/res/screenshot.png +0 -0
- package/res/vue.global.js +0 -18552
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<!-- 添加提供商模态框 -->
|
|
2
|
+
<div v-if="showAddModal" class="modal-overlay" @click.self="closeAddModal">
|
|
3
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="add-provider-modal-title">
|
|
4
|
+
<div class="modal-title" id="add-provider-modal-title">添加提供商</div>
|
|
5
|
+
|
|
6
|
+
<div class="form-group">
|
|
7
|
+
<label class="form-label">名称</label>
|
|
8
|
+
<input
|
|
9
|
+
v-model="newProvider.name"
|
|
10
|
+
:class="['form-input', { invalid: !!providerFieldError('add', 'name') }]"
|
|
11
|
+
placeholder="例如: myapi"
|
|
12
|
+
autocomplete="off"
|
|
13
|
+
spellcheck="false"
|
|
14
|
+
@blur="normalizeProviderDraft('add')">
|
|
15
|
+
<div v-if="providerFieldError('add', 'name')" class="form-hint form-error">{{ providerFieldError('add', 'name') }}</div>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="form-group">
|
|
18
|
+
<label class="form-label">API 端点</label>
|
|
19
|
+
<input
|
|
20
|
+
v-model="newProvider.url"
|
|
21
|
+
:class="['form-input', { invalid: !!providerFieldError('add', 'url') }]"
|
|
22
|
+
placeholder="https://api.example.com/v1"
|
|
23
|
+
autocomplete="off"
|
|
24
|
+
spellcheck="false"
|
|
25
|
+
@blur="normalizeProviderDraft('add')">
|
|
26
|
+
<div v-if="providerFieldError('add', 'url')" class="form-hint form-error">{{ providerFieldError('add', 'url') }}</div>
|
|
27
|
+
</div>
|
|
28
|
+
<div class="form-group">
|
|
29
|
+
<label class="form-label">认证密钥</label>
|
|
30
|
+
<input v-model="newProvider.key" class="form-input" type="password" placeholder="sk-...">
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="btn-group">
|
|
34
|
+
<button class="btn btn-cancel" @click="closeAddModal">取消</button>
|
|
35
|
+
<button class="btn btn-confirm" @click="addProvider" :disabled="!canSubmitProvider('add')">添加</button>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
|
|
40
|
+
<!-- 编辑提供商模态框 -->
|
|
41
|
+
<div v-if="showEditModal" class="modal-overlay" @click.self="closeEditModal">
|
|
42
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="edit-provider-modal-title">
|
|
43
|
+
<div class="modal-title" id="edit-provider-modal-title">编辑提供商</div>
|
|
44
|
+
|
|
45
|
+
<div class="form-group">
|
|
46
|
+
<label class="form-label">名称</label>
|
|
47
|
+
<input v-model="editingProvider.name" class="form-input" placeholder="提供商名称" readonly>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="form-group">
|
|
50
|
+
<label class="form-label">API 端点</label>
|
|
51
|
+
<input
|
|
52
|
+
v-model="editingProvider.url"
|
|
53
|
+
:class="['form-input', { invalid: !!providerFieldError('edit', 'url') }]"
|
|
54
|
+
placeholder="https://api.example.com/v1"
|
|
55
|
+
autocomplete="off"
|
|
56
|
+
spellcheck="false"
|
|
57
|
+
@blur="normalizeProviderDraft('edit')">
|
|
58
|
+
<div v-if="providerFieldError('edit', 'url')" class="form-hint form-error">{{ providerFieldError('edit', 'url') }}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="form-group">
|
|
61
|
+
<label class="form-label">认证密钥</label>
|
|
62
|
+
<input v-model="editingProvider.key" class="form-input" type="password" placeholder="留空则保持不变">
|
|
63
|
+
<div class="form-hint">留空表示不修改密钥</div>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<div class="btn-group">
|
|
67
|
+
<button class="btn btn-cancel" @click="closeEditModal">取消</button>
|
|
68
|
+
<button class="btn btn-confirm" @click="updateProvider" :disabled="!canSubmitProvider('edit')">保存</button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<!-- 添加模型模态框 -->
|
|
74
|
+
<div v-if="showModelModal" class="modal-overlay" @click.self="closeModelModal">
|
|
75
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="add-model-modal-title">
|
|
76
|
+
<div class="modal-title" id="add-model-modal-title">添加模型</div>
|
|
77
|
+
|
|
78
|
+
<div class="form-group">
|
|
79
|
+
<label class="form-label">模型名称</label>
|
|
80
|
+
<input v-model="newModelName" class="form-input" placeholder="例如: gpt-5">
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<div class="btn-group">
|
|
84
|
+
<button class="btn btn-cancel" @click="closeModelModal">取消</button>
|
|
85
|
+
<button class="btn btn-confirm" @click="addModel">添加</button>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- 模型列表模态框 -->
|
|
91
|
+
<div v-if="showModelListModal" class="modal-overlay" @click.self="showModelListModal = false">
|
|
92
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="manage-models-modal-title">
|
|
93
|
+
<div class="modal-title" id="manage-models-modal-title">管理模型</div>
|
|
94
|
+
|
|
95
|
+
<div class="model-list">
|
|
96
|
+
<div v-for="model in models" :key="model" class="model-item">
|
|
97
|
+
<span>{{ model }}</span>
|
|
98
|
+
<button type="button" class="btn-remove-model" @click="removeModel(model)">删除</button>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<div class="btn-group">
|
|
103
|
+
<button class="btn btn-confirm" @click="showModelListModal = false">关闭</button>
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- 添加Claude配置模态框 -->
|
|
109
|
+
<div v-if="showClaudeConfigModal" class="modal-overlay" @click.self="closeClaudeConfigModal">
|
|
110
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="add-claude-config-modal-title">
|
|
111
|
+
<div class="modal-title" id="add-claude-config-modal-title">添加 Claude Code 配置</div>
|
|
112
|
+
|
|
113
|
+
<div class="form-group">
|
|
114
|
+
<label class="form-label">配置名称</label>
|
|
115
|
+
<input v-model="newClaudeConfig.name" class="form-input" placeholder="例如: 智谱GLM">
|
|
116
|
+
</div>
|
|
117
|
+
<div class="form-group">
|
|
118
|
+
<label class="form-label">API Key</label>
|
|
119
|
+
<input v-model="newClaudeConfig.apiKey" class="form-input" type="password" autocomplete="off" spellcheck="false" placeholder="sk-ant-...">
|
|
120
|
+
</div>
|
|
121
|
+
<div class="form-group">
|
|
122
|
+
<label class="form-label">Base URL</label>
|
|
123
|
+
<input v-model="newClaudeConfig.baseUrl" class="form-input" placeholder="https://open.bigmodel.cn/api/anthropic">
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="btn-group">
|
|
127
|
+
<button class="btn btn-cancel" @click="closeClaudeConfigModal">取消</button>
|
|
128
|
+
<button class="btn btn-confirm" @click="addClaudeConfig">添加</button>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
|
|
133
|
+
<!-- 编辑Claude配置模态框 -->
|
|
134
|
+
<div v-if="showEditConfigModal" class="modal-overlay" @click.self="closeEditConfigModal">
|
|
135
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="edit-claude-config-modal-title">
|
|
136
|
+
<div class="modal-title" id="edit-claude-config-modal-title">编辑 Claude Code 配置</div>
|
|
137
|
+
|
|
138
|
+
<div class="form-group">
|
|
139
|
+
<label class="form-label">配置名称</label>
|
|
140
|
+
<input v-model="editingConfig.name" class="form-input" placeholder="配置名称" readonly>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="form-group">
|
|
143
|
+
<label class="form-label">API Key</label>
|
|
144
|
+
<input v-model="editingConfig.apiKey" class="form-input" type="password" autocomplete="off" spellcheck="false" placeholder="sk-ant-...">
|
|
145
|
+
</div>
|
|
146
|
+
<div class="form-group">
|
|
147
|
+
<label class="form-label">Base URL</label>
|
|
148
|
+
<input v-model="editingConfig.baseUrl" class="form-input" placeholder="https://open.bigmodel.cn/api/anthropic">
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
<div class="btn-group">
|
|
152
|
+
<button class="btn btn-cancel" @click="closeEditConfigModal">取消</button>
|
|
153
|
+
<button class="btn btn-confirm" @click="saveAndApplyConfig">保存并应用</button>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
<!-- Claude Code 配置模式 -->
|
|
2
|
+
<div
|
|
3
|
+
v-show="mainTab === 'config' && configMode === 'claude'"
|
|
4
|
+
class="mode-content mode-cards"
|
|
5
|
+
id="panel-config-claude"
|
|
6
|
+
role="tabpanel"
|
|
7
|
+
:aria-labelledby="'tab-config-claude'">
|
|
8
|
+
<!-- 添加提供商按钮 -->
|
|
9
|
+
<button class="btn-add" @click="openClaudeConfigModal" v-if="!loading && !initError">
|
|
10
|
+
<svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
|
|
11
|
+
<path d="M10 4v12M4 10h12"/>
|
|
12
|
+
</svg>
|
|
13
|
+
添加提供商
|
|
14
|
+
</button>
|
|
15
|
+
<div class="config-template-hint">
|
|
16
|
+
默认应用到 <code>~/.claude/settings.json</code>。
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
<div class="selector-section">
|
|
20
|
+
<div class="selector-header">
|
|
21
|
+
<span class="selector-title">预设供应商</span>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="btn-group" style="flex-wrap: wrap; gap: 8px;">
|
|
24
|
+
<button type="button" class="btn-mini" @click="closeClaudeConfigModal(); showClaudeConfigModal = true">自定义配置</button>
|
|
25
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Claude Official'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.anthropic.com'; newClaudeConfig.model = 'claude-sonnet-4'; showClaudeConfigModal = true">Claude Official</button>
|
|
26
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'DeepSeek'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.deepseek.com/anthropic'; newClaudeConfig.model = 'DeepSeek-V3.2'; showClaudeConfigModal = true">DeepSeek</button>
|
|
27
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Zhipu GLM'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://open.bigmodel.cn/api/anthropic'; newClaudeConfig.model = 'glm-5'; showClaudeConfigModal = true">Zhipu GLM</button>
|
|
28
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Z.ai GLM'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.z.ai/api/anthropic'; newClaudeConfig.model = 'glm-5'; showClaudeConfigModal = true">Z.ai GLM</button>
|
|
29
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Qwen Coder'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://coding.dashscope.aliyuncs.com/apps/anthropic'; newClaudeConfig.model = 'qwen3-coder'; showClaudeConfigModal = true">Qwen Coder</button>
|
|
30
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Kimi k2'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.moonshot.cn/anthropic'; newClaudeConfig.model = 'kimi-k2.5'; showClaudeConfigModal = true">Kimi k2</button>
|
|
31
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Kimi For Coding'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.kimi.com/coding/'; newClaudeConfig.model = 'kimi-k2.5'; showClaudeConfigModal = true">Kimi For Coding</button>
|
|
32
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'KAT-Coder'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://vanchin.streamlake.ai/api/gateway/v1/endpoints/${ENDPOINT_ID}/claude-code-proxy'; newClaudeConfig.model = 'KAT-Coder-Pro V1'; showClaudeConfigModal = true">KAT-Coder</button>
|
|
33
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'Longcat'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.longcat.chat/anthropic'; newClaudeConfig.model = 'LongCat-Flash-Chat'; showClaudeConfigModal = true">Longcat</button>
|
|
34
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'MiniMax'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.minimaxi.com/anthropic'; newClaudeConfig.model = 'MiniMax-M2.7'; showClaudeConfigModal = true">MiniMax</button>
|
|
35
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'MiniMax en'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.minimax.io/anthropic'; newClaudeConfig.model = 'MiniMax-M2.7'; showClaudeConfigModal = true">MiniMax en</button>
|
|
36
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'DouBaoSeed'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://ark.cn-beijing.volces.com/api/coding'; newClaudeConfig.model = 'doubao-seed-2-0-code-preview-latest'; showClaudeConfigModal = true">DouBaoSeed</button>
|
|
37
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'BaiLing'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api.tbox.cn/api/anthropic'; newClaudeConfig.model = 'Ling-2.5-1T'; showClaudeConfigModal = true">BaiLing</button>
|
|
38
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'ModelScope'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://api-inference.modelscope.cn'; newClaudeConfig.model = 'ZhipuAI/GLM-5'; showClaudeConfigModal = true">ModelScope</button>
|
|
39
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'AiHubMix'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://aihubmix.com'; newClaudeConfig.model = 'glm-4.7'; showClaudeConfigModal = true">AiHubMix</button>
|
|
40
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'DMXAPI'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://www.dmxapi.cn'; newClaudeConfig.model = 'glm-4.7'; showClaudeConfigModal = true">DMXAPI</button>
|
|
41
|
+
<button type="button" class="btn-mini" @click="newClaudeConfig.name = 'PackyCode'; newClaudeConfig.apiKey = ''; newClaudeConfig.baseUrl = 'https://www.packyapi.com'; newClaudeConfig.model = 'glm-4.7'; showClaudeConfigModal = true">PackyCode</button>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="selector-section">
|
|
46
|
+
<div class="selector-header">
|
|
47
|
+
<span class="selector-title">模型</span>
|
|
48
|
+
</div>
|
|
49
|
+
<select
|
|
50
|
+
v-if="claudeModelHasList"
|
|
51
|
+
class="model-select"
|
|
52
|
+
v-model="currentClaudeModel"
|
|
53
|
+
@change="onClaudeModelChange"
|
|
54
|
+
>
|
|
55
|
+
<option v-for="model in claudeModelOptions" :key="model" :value="model">{{ model }}</option>
|
|
56
|
+
</select>
|
|
57
|
+
<input
|
|
58
|
+
v-else
|
|
59
|
+
class="model-input"
|
|
60
|
+
v-model="currentClaudeModel"
|
|
61
|
+
@blur="onClaudeModelChange"
|
|
62
|
+
@keyup.enter="onClaudeModelChange"
|
|
63
|
+
placeholder="例如: claude-3-7-sonnet"
|
|
64
|
+
>
|
|
65
|
+
<div class="config-template-hint">
|
|
66
|
+
模型修改后会自动保存并应用到当前配置。
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="selector-section">
|
|
71
|
+
<div class="selector-header">
|
|
72
|
+
<span class="selector-title">配置健康检查</span>
|
|
73
|
+
</div>
|
|
74
|
+
<button class="btn-tool" @click="runHealthCheck" :disabled="healthCheckLoading || loading || !!initError">
|
|
75
|
+
{{ healthCheckLoading ? '检查中...' : '运行检查' }}
|
|
76
|
+
</button>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="card-list">
|
|
80
|
+
<div v-for="(config, name) in claudeConfigs" :key="name"
|
|
81
|
+
:class="['card', { active: currentClaudeConfig === name }]"
|
|
82
|
+
@click="applyClaudeConfig(name)"
|
|
83
|
+
@keydown.enter.self.prevent="applyClaudeConfig(name)"
|
|
84
|
+
@keydown.space.self.prevent="applyClaudeConfig(name)"
|
|
85
|
+
tabindex="0"
|
|
86
|
+
role="button"
|
|
87
|
+
:aria-current="currentClaudeConfig === name ? 'true' : null">
|
|
88
|
+
<div class="card-leading">
|
|
89
|
+
<div class="card-icon">{{ name.charAt(0).toUpperCase() }}</div>
|
|
90
|
+
<div class="card-content">
|
|
91
|
+
<div class="card-title">{{ name }}</div>
|
|
92
|
+
<div class="card-subtitle">{{ config.model || '未设置模型' }}</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
<div class="card-trailing">
|
|
96
|
+
<span :class="['pill', config.hasKey ? 'configured' : 'empty']">
|
|
97
|
+
{{ config.hasKey ? '已配置' : '未配置' }}
|
|
98
|
+
</span>
|
|
99
|
+
<span v-if="claudeSpeedResults[name]" :class="['latency', claudeSpeedResults[name].ok ? 'ok' : 'error']">
|
|
100
|
+
{{ formatLatency(claudeSpeedResults[name]) }}
|
|
101
|
+
</span>
|
|
102
|
+
<div class="card-actions" @click.stop>
|
|
103
|
+
<button class="card-action-btn" @click="openEditConfigModal(name)" :aria-label="`Edit Claude config ${name}`" title="编辑">
|
|
104
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
105
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
106
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
107
|
+
</svg>
|
|
108
|
+
</button>
|
|
109
|
+
<button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled title="分享导入命令(暂时禁用)" aria-label="Share import command">
|
|
110
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
111
|
+
<path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
|
|
112
|
+
<path d="M16 6l-4-4-4 4"/>
|
|
113
|
+
<path d="M12 2v14"/>
|
|
114
|
+
</svg>
|
|
115
|
+
</button>
|
|
116
|
+
<button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="`Delete Claude config ${name}`" title="删除">
|
|
117
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
118
|
+
<path d="M3 6h18"/>
|
|
119
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
120
|
+
</svg>
|
|
121
|
+
</button>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<!-- Provider 配置模式(Codex) -->
|
|
2
|
+
<div
|
|
3
|
+
v-show="mainTab === 'config' && isProviderConfigMode"
|
|
4
|
+
class="mode-content mode-cards"
|
|
5
|
+
id="panel-config-provider"
|
|
6
|
+
role="tabpanel"
|
|
7
|
+
:aria-labelledby="'tab-config-' + configMode">
|
|
8
|
+
<!-- 添加提供商按钮 -->
|
|
9
|
+
<button class="btn-add" @click="showAddModal = true" v-if="!loading && !initError">
|
|
10
|
+
<svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
|
|
11
|
+
<path d="M10 4v12M4 10h12"/>
|
|
12
|
+
</svg>
|
|
13
|
+
新增提供商
|
|
14
|
+
</button>
|
|
15
|
+
|
|
16
|
+
<!-- 模型选择器 -->
|
|
17
|
+
<div class="selector-section">
|
|
18
|
+
<div class="selector-header">
|
|
19
|
+
<span class="selector-title">模型</span>
|
|
20
|
+
<div class="selector-actions">
|
|
21
|
+
<button class="btn-icon" @click="showModelModal = true" aria-label="Add model" title="添加模型" v-if="modelsSource === 'legacy'">+</button>
|
|
22
|
+
<button class="btn-icon" @click="showModelListModal = true" aria-label="Manage models" title="管理模型" v-if="modelsSource === 'legacy'">≡</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
<select
|
|
26
|
+
v-if="codexModelsLoading || modelsSource === 'remote'"
|
|
27
|
+
class="model-select"
|
|
28
|
+
v-model="currentModel"
|
|
29
|
+
@change="onModelChange"
|
|
30
|
+
:disabled="codexModelsLoading"
|
|
31
|
+
>
|
|
32
|
+
<option v-if="codexModelsLoading" value="">加载中...</option>
|
|
33
|
+
<option v-else v-for="model in models" :key="model" :value="model">{{ model }}</option>
|
|
34
|
+
</select>
|
|
35
|
+
<input
|
|
36
|
+
v-if="!codexModelsLoading && (modelsSource !== 'remote' || !modelsHasCurrent)"
|
|
37
|
+
class="model-input"
|
|
38
|
+
v-model="currentModel"
|
|
39
|
+
@blur="onModelChange"
|
|
40
|
+
:placeholder="activeProviderModelPlaceholder"
|
|
41
|
+
>
|
|
42
|
+
<div class="config-template-hint" v-if="modelsSource === 'unlimited'">
|
|
43
|
+
当前无模型列表,可手填。
|
|
44
|
+
</div>
|
|
45
|
+
<div class="config-template-hint" v-if="modelsSource === 'error'">
|
|
46
|
+
模型列表获取失败,可手填。
|
|
47
|
+
</div>
|
|
48
|
+
<div class="config-template-hint" v-if="modelsSource === 'remote' && !modelsHasCurrent">
|
|
49
|
+
{{ isCodexConfigMode ? '当前模型不在列表,可手填或改模板。' : '当前模型不在列表,可手填。' }}
|
|
50
|
+
</div>
|
|
51
|
+
<div class="config-template-hint" v-if="isCodexConfigMode">
|
|
52
|
+
先改模板,再应用。
|
|
53
|
+
</div>
|
|
54
|
+
<div class="config-template-hint" v-else-if="activeProviderBridgeHint">
|
|
55
|
+
{{ activeProviderBridgeHint }} 模板仅限 Codex 编辑。
|
|
56
|
+
</div>
|
|
57
|
+
<button class="btn-tool btn-template-editor" v-if="isCodexConfigMode" @click="openConfigTemplateEditor" :disabled="loading || !!initError">
|
|
58
|
+
打开模板编辑器
|
|
59
|
+
</button>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<template v-if="isCodexConfigMode">
|
|
63
|
+
<div class="selector-section">
|
|
64
|
+
<div class="selector-header">
|
|
65
|
+
<span class="selector-title">服务档</span>
|
|
66
|
+
</div>
|
|
67
|
+
<select class="model-select" v-model="serviceTier" @change="onServiceTierChange">
|
|
68
|
+
<option value="fast">fast(默认)</option>
|
|
69
|
+
<option value="standard">standard</option>
|
|
70
|
+
</select>
|
|
71
|
+
<div class="config-template-hint">
|
|
72
|
+
仅 fast 写入 <code>service_tier</code>。
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<div class="selector-section">
|
|
77
|
+
<div class="selector-header">
|
|
78
|
+
<span class="selector-title">推理强度</span>
|
|
79
|
+
</div>
|
|
80
|
+
<select class="model-select" v-model="modelReasoningEffort" @change="onReasoningEffortChange">
|
|
81
|
+
<option value="high">high</option>
|
|
82
|
+
<option value="medium">medium(默认)</option>
|
|
83
|
+
<option value="low">low</option>
|
|
84
|
+
<option value="xhigh">xhigh</option>
|
|
85
|
+
</select>
|
|
86
|
+
<div class="config-template-hint">
|
|
87
|
+
控制推理深度;high 更深。
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div class="selector-section">
|
|
92
|
+
<div class="selector-header">
|
|
93
|
+
<span class="selector-title">压缩阈值</span>
|
|
94
|
+
<div class="selector-actions">
|
|
95
|
+
<button
|
|
96
|
+
class="btn-tool btn-tool-compact"
|
|
97
|
+
@click="resetCodexContextBudgetDefaults"
|
|
98
|
+
:disabled="loading || !!initError || codexApplying">
|
|
99
|
+
重置
|
|
100
|
+
</button>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="codex-config-grid">
|
|
104
|
+
<div class="form-group codex-config-field">
|
|
105
|
+
<label class="form-label" for="codex-model-context-window">model_context_window</label>
|
|
106
|
+
<input
|
|
107
|
+
id="codex-model-context-window"
|
|
108
|
+
v-model="modelContextWindowInput"
|
|
109
|
+
class="form-input"
|
|
110
|
+
inputmode="numeric"
|
|
111
|
+
autocomplete="off"
|
|
112
|
+
placeholder="例如: 190000"
|
|
113
|
+
@focus="editingCodexBudgetField = 'modelContextWindowInput'"
|
|
114
|
+
@input="sanitizePositiveIntegerDraft('modelContextWindowInput')"
|
|
115
|
+
@blur="onModelContextWindowBlur"
|
|
116
|
+
@keydown.enter.prevent="onModelContextWindowBlur">
|
|
117
|
+
<div class="form-hint">上下文上限,默认 190000。</div>
|
|
118
|
+
</div>
|
|
119
|
+
<div class="form-group codex-config-field">
|
|
120
|
+
<label class="form-label" for="codex-model-auto-compact-token-limit">model_auto_compact_token_limit</label>
|
|
121
|
+
<input
|
|
122
|
+
id="codex-model-auto-compact-token-limit"
|
|
123
|
+
v-model="modelAutoCompactTokenLimitInput"
|
|
124
|
+
class="form-input"
|
|
125
|
+
inputmode="numeric"
|
|
126
|
+
autocomplete="off"
|
|
127
|
+
placeholder="例如: 185000"
|
|
128
|
+
@focus="editingCodexBudgetField = 'modelAutoCompactTokenLimitInput'"
|
|
129
|
+
@input="sanitizePositiveIntegerDraft('modelAutoCompactTokenLimitInput')"
|
|
130
|
+
@blur="onModelAutoCompactTokenLimitBlur"
|
|
131
|
+
@keydown.enter.prevent="onModelAutoCompactTokenLimitBlur">
|
|
132
|
+
<div class="form-hint">自动压缩阈值,默认 185000。</div>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div class="selector-section">
|
|
138
|
+
<div class="selector-header">
|
|
139
|
+
<span class="selector-title">AGENTS.md</span>
|
|
140
|
+
</div>
|
|
141
|
+
<button class="btn-tool" @click="openAgentsEditor" :disabled="loading || !!initError || agentsLoading">
|
|
142
|
+
{{ agentsLoading ? '加载中...' : '打开 AGENTS.md' }}
|
|
143
|
+
</button>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
</template>
|
|
147
|
+
|
|
148
|
+
<div class="selector-section">
|
|
149
|
+
<div class="selector-header">
|
|
150
|
+
<span class="selector-title">健康检测</span>
|
|
151
|
+
</div>
|
|
152
|
+
<button class="btn-tool" @click="openHealthCheckDialog()" :disabled="loading || !!initError">
|
|
153
|
+
检测对话
|
|
154
|
+
</button>
|
|
155
|
+
</div>
|
|
156
|
+
|
|
157
|
+
<div v-if="!loading && !initError" class="card-list">
|
|
158
|
+
<div v-for="provider in displayProvidersList" :key="provider.name"
|
|
159
|
+
:class="['card', { active: displayCurrentProvider === provider.name }]"
|
|
160
|
+
@click="switchProvider(provider.name)"
|
|
161
|
+
@keydown.enter.self.prevent="switchProvider(provider.name)"
|
|
162
|
+
@keydown.space.self.prevent="switchProvider(provider.name)"
|
|
163
|
+
tabindex="0"
|
|
164
|
+
role="button"
|
|
165
|
+
:aria-current="displayCurrentProvider === provider.name ? 'true' : null">
|
|
166
|
+
<div class="card-leading">
|
|
167
|
+
<div class="card-icon">{{ provider.name.charAt(0).toUpperCase() }}</div>
|
|
168
|
+
<div class="card-content">
|
|
169
|
+
<div class="card-title">
|
|
170
|
+
<span>{{ provider.name }}</span>
|
|
171
|
+
<span v-if="provider.readOnly" class="provider-readonly-badge">系统</span>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="card-subtitle">
|
|
174
|
+
{{ provider.url || '未设 URL' }}
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
<div class="card-trailing">
|
|
179
|
+
<span :class="['pill', providerPillConfigured(provider) ? 'configured' : 'empty']">
|
|
180
|
+
{{ providerPillText(provider) }}
|
|
181
|
+
</span>
|
|
182
|
+
<span v-if="speedResults[provider.name]" :class="['latency', speedResults[provider.name].ok ? 'ok' : 'error']">
|
|
183
|
+
{{ formatLatency(speedResults[provider.name]) }}
|
|
184
|
+
</span>
|
|
185
|
+
<div class="card-actions" @click.stop>
|
|
186
|
+
<button class="card-action-btn" @click="openHealthCheckDialog({ providerName: provider.name, locked: true })" :aria-label="`Open health dialog for ${provider.name}`" title="检测对话">
|
|
187
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
188
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
|
|
189
|
+
<path d="M8 9h8"/>
|
|
190
|
+
<path d="M8 13h5"/>
|
|
191
|
+
</svg>
|
|
192
|
+
</button>
|
|
193
|
+
<button
|
|
194
|
+
v-if="!provider.readOnly"
|
|
195
|
+
class="card-action-btn"
|
|
196
|
+
:class="{ loading: providerShareLoading[provider.name], disabled: !shouldAllowProviderShare(provider) }"
|
|
197
|
+
:disabled="providerShareLoading[provider.name] || !shouldAllowProviderShare(provider)"
|
|
198
|
+
@click="copyProviderShareCommand(provider)"
|
|
199
|
+
:title="shouldAllowProviderShare(provider) ? '分享命令' : '不可分享'"
|
|
200
|
+
aria-label="Share import command">
|
|
201
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
202
|
+
<path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
|
|
203
|
+
<path d="M16 6l-4-4-4 4"/>
|
|
204
|
+
<path d="M12 2v14"/>
|
|
205
|
+
</svg>
|
|
206
|
+
</button>
|
|
207
|
+
<button
|
|
208
|
+
v-if="!provider.readOnly"
|
|
209
|
+
class="card-action-btn"
|
|
210
|
+
:class="{ disabled: !shouldShowProviderEdit(provider) }"
|
|
211
|
+
:disabled="!shouldShowProviderEdit(provider)"
|
|
212
|
+
@click="openEditModal(provider)"
|
|
213
|
+
:aria-label="`Edit provider ${provider.name}`"
|
|
214
|
+
:title="shouldShowProviderEdit(provider) ? '编辑' : '不可编辑'">
|
|
215
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
216
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
217
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
218
|
+
</svg>
|
|
219
|
+
</button>
|
|
220
|
+
<button
|
|
221
|
+
v-if="!provider.readOnly"
|
|
222
|
+
class="card-action-btn delete"
|
|
223
|
+
:class="{ disabled: !shouldShowProviderDelete(provider) }"
|
|
224
|
+
:disabled="!shouldShowProviderDelete(provider)"
|
|
225
|
+
@click="deleteProvider(provider.name)"
|
|
226
|
+
:aria-label="`Delete provider ${provider.name}`"
|
|
227
|
+
:title="shouldShowProviderDelete(provider) ? '删除' : '不可删除'">
|
|
228
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
229
|
+
<path d="M3 6h18"/>
|
|
230
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
231
|
+
</svg>
|
|
232
|
+
</button>
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!-- OpenClaw 配置模式 -->
|
|
2
|
+
<div
|
|
3
|
+
v-show="mainTab === 'config' && configMode === 'openclaw'"
|
|
4
|
+
class="mode-content mode-cards"
|
|
5
|
+
id="panel-config-openclaw"
|
|
6
|
+
role="tabpanel"
|
|
7
|
+
:aria-labelledby="'tab-config-openclaw'">
|
|
8
|
+
<div class="config-template-hint">
|
|
9
|
+
写入 <code>~/.openclaw/openclaw.json</code>,支持 JSON5。
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<div class="selector-section">
|
|
13
|
+
<div class="selector-header">
|
|
14
|
+
<span class="selector-title">AGENTS.md</span>
|
|
15
|
+
</div>
|
|
16
|
+
<div class="config-template-hint">
|
|
17
|
+
读写 Workspace 的 <code>AGENTS.md</code>,默认路径 <code>~/.openclaw/workspace/AGENTS.md</code>。
|
|
18
|
+
</div>
|
|
19
|
+
<button class="btn-tool" @click="openOpenclawAgentsEditor" :disabled="loading || !!initError || agentsLoading">
|
|
20
|
+
{{ agentsLoading ? '加载中...' : '打开 AGENTS.md' }}
|
|
21
|
+
</button>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="selector-section">
|
|
25
|
+
<div class="selector-header">
|
|
26
|
+
<label class="selector-title" for="openclaw-workspace-file">工作区文件</label>
|
|
27
|
+
</div>
|
|
28
|
+
<input
|
|
29
|
+
id="openclaw-workspace-file"
|
|
30
|
+
class="form-input"
|
|
31
|
+
v-model="openclawWorkspaceFileName"
|
|
32
|
+
placeholder="例如: SOUL.md">
|
|
33
|
+
<div class="config-template-hint">
|
|
34
|
+
仅限 Workspace 内的 <code>.md</code> 文件。
|
|
35
|
+
</div>
|
|
36
|
+
<button class="btn-tool" @click="openOpenclawWorkspaceEditor" :disabled="loading || !!initError || agentsLoading">
|
|
37
|
+
{{ agentsLoading ? '加载中...' : '打开工作区文件' }}
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="card-list">
|
|
42
|
+
<div v-for="(config, name) in openclawConfigs" :key="name"
|
|
43
|
+
:class="['card', { active: currentOpenclawConfig === name }]"
|
|
44
|
+
@click="applyOpenclawConfig(name)"
|
|
45
|
+
@keydown.enter.self.prevent="applyOpenclawConfig(name)"
|
|
46
|
+
@keydown.space.self.prevent="applyOpenclawConfig(name)"
|
|
47
|
+
tabindex="0"
|
|
48
|
+
role="button"
|
|
49
|
+
:aria-current="currentOpenclawConfig === name ? 'true' : null">
|
|
50
|
+
<div class="card-leading">
|
|
51
|
+
<div class="card-icon">{{ name.charAt(0).toUpperCase() }}</div>
|
|
52
|
+
<div class="card-content">
|
|
53
|
+
<div class="card-title">{{ name }}</div>
|
|
54
|
+
<div class="card-subtitle">{{ openclawSubtitle(config) }}</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div class="card-trailing">
|
|
58
|
+
<span :class="['pill', openclawHasContent(config) ? 'configured' : 'empty']">
|
|
59
|
+
{{ openclawHasContent(config) ? '已配置' : '未配置' }}
|
|
60
|
+
</span>
|
|
61
|
+
<div class="card-actions" @click.stop>
|
|
62
|
+
<button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="`Edit OpenClaw config ${name}`" title="编辑">
|
|
63
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
64
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
65
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
66
|
+
</svg>
|
|
67
|
+
</button>
|
|
68
|
+
<button v-if="name !== '默认配置'" class="card-action-btn delete" @click="deleteOpenclawConfig(name)" :aria-label="`Delete OpenClaw config ${name}`" title="删除">
|
|
69
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
70
|
+
<path d="M3 6h18"/>
|
|
71
|
+
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
|
72
|
+
</svg>
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</div>
|