codexmate 0.0.3 → 0.0.4
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/.github/workflows/release.yml +42 -42
- package/README.md +93 -74
- package/README.zh-CN.md +96 -77
- package/cli.js +237 -66
- package/cmd/publish-npm.cmd +65 -65
- package/package.json +27 -25
- package/res/screenshot.png +0 -0
- package/web-ui.html +494 -131
package/web-ui.html
CHANGED
|
@@ -1666,20 +1666,23 @@
|
|
|
1666
1666
|
Codex<br>
|
|
1667
1667
|
<span class="accent">Mate.</span>
|
|
1668
1668
|
</h1>
|
|
1669
|
-
<p class="subtitle">本地配置中枢,统一管理 Codex / Claude Code / 会话。</p>
|
|
1669
|
+
<p class="subtitle">本地配置中枢,统一管理 Codex / Claude Code / OpenClaw / 会话。</p>
|
|
1670
1670
|
|
|
1671
1671
|
<!-- 模式切换器 -->
|
|
1672
|
-
<div class="segmented-control">
|
|
1673
|
-
<button :class="['segment', { active: configMode === 'codex' }]" @click="switchConfigMode('codex')">
|
|
1674
|
-
Codex 配置
|
|
1675
|
-
</button>
|
|
1676
|
-
<button :class="['segment', { active: configMode === 'claude' }]" @click="switchConfigMode('claude')">
|
|
1677
|
-
Claude Code 配置
|
|
1678
|
-
</button>
|
|
1679
|
-
<button :class="['segment', { active: configMode === '
|
|
1680
|
-
|
|
1681
|
-
</button>
|
|
1682
|
-
|
|
1672
|
+
<div class="segmented-control">
|
|
1673
|
+
<button :class="['segment', { active: configMode === 'codex' }]" @click="switchConfigMode('codex')">
|
|
1674
|
+
Codex 配置
|
|
1675
|
+
</button>
|
|
1676
|
+
<button :class="['segment', { active: configMode === 'claude' }]" @click="switchConfigMode('claude')">
|
|
1677
|
+
Claude Code 配置
|
|
1678
|
+
</button>
|
|
1679
|
+
<button :class="['segment', { active: configMode === 'openclaw' }]" @click="switchConfigMode('openclaw')">
|
|
1680
|
+
OpenClaw 配置
|
|
1681
|
+
</button>
|
|
1682
|
+
<button :class="['segment', { active: configMode === 'sessions' }]" @click="switchConfigMode('sessions')">
|
|
1683
|
+
会话浏览
|
|
1684
|
+
</button>
|
|
1685
|
+
</div>
|
|
1683
1686
|
|
|
1684
1687
|
<!-- 内容包裹器 - 稳定布局 -->
|
|
1685
1688
|
<div class="content-wrapper">
|
|
@@ -1767,10 +1770,10 @@
|
|
|
1767
1770
|
</div>
|
|
1768
1771
|
</div>
|
|
1769
1772
|
|
|
1770
|
-
<!-- Claude Code 配置模式 -->
|
|
1771
|
-
<div v-show="configMode === 'claude'" class="mode-content">
|
|
1772
|
-
<!-- 添加提供商按钮 -->
|
|
1773
|
-
<button class="btn-add" @click="showClaudeConfigModal = true" v-if="!loading && !initError">
|
|
1773
|
+
<!-- Claude Code 配置模式 -->
|
|
1774
|
+
<div v-show="configMode === 'claude'" class="mode-content">
|
|
1775
|
+
<!-- 添加提供商按钮 -->
|
|
1776
|
+
<button class="btn-add" @click="showClaudeConfigModal = true" v-if="!loading && !initError">
|
|
1774
1777
|
<svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
|
|
1775
1778
|
<path d="M10 4v12M4 10h12"/>
|
|
1776
1779
|
</svg>
|
|
@@ -1811,11 +1814,69 @@
|
|
|
1811
1814
|
</div>
|
|
1812
1815
|
</div>
|
|
1813
1816
|
</div>
|
|
1814
|
-
</div>
|
|
1815
|
-
</div>
|
|
1816
|
-
|
|
1817
|
-
<!--
|
|
1818
|
-
<div v-show="configMode === '
|
|
1817
|
+
</div>
|
|
1818
|
+
</div>
|
|
1819
|
+
|
|
1820
|
+
<!-- OpenClaw 配置模式 -->
|
|
1821
|
+
<div v-show="configMode === 'openclaw'" class="mode-content">
|
|
1822
|
+
<button class="btn-add" @click="openOpenclawAddModal" v-if="!loading && !initError">
|
|
1823
|
+
<svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
|
|
1824
|
+
<path d="M10 4v12M4 10h12"/>
|
|
1825
|
+
</svg>
|
|
1826
|
+
添加 OpenClaw 配置
|
|
1827
|
+
</button>
|
|
1828
|
+
<div class="config-template-hint">
|
|
1829
|
+
默认应用到 <code>~/.openclaw/openclaw.json</code>;支持 JSON5(注释/尾逗号)。
|
|
1830
|
+
</div>
|
|
1831
|
+
|
|
1832
|
+
<div class="selector-section">
|
|
1833
|
+
<div class="selector-header">
|
|
1834
|
+
<span class="selector-title">AGENTS.md</span>
|
|
1835
|
+
</div>
|
|
1836
|
+
<div class="config-template-hint">
|
|
1837
|
+
管理 OpenClaw Workspace 指令文件,默认读写 <code>~/.openclaw/workspace/AGENTS.md</code>。
|
|
1838
|
+
</div>
|
|
1839
|
+
<button class="btn-tool" @click="openOpenclawAgentsEditor" :disabled="loading || !!initError || agentsLoading">
|
|
1840
|
+
{{ agentsLoading ? '加载中...' : '打开 AGENTS.md 编辑器' }}
|
|
1841
|
+
</button>
|
|
1842
|
+
</div>
|
|
1843
|
+
|
|
1844
|
+
<div class="card-list">
|
|
1845
|
+
<div v-for="(config, name) in openclawConfigs" :key="name"
|
|
1846
|
+
:class="['card', { active: currentOpenclawConfig === name }]"
|
|
1847
|
+
@click="applyOpenclawConfig(name)">
|
|
1848
|
+
<div class="card-leading">
|
|
1849
|
+
<div class="card-icon">{{ name.charAt(0).toUpperCase() }}</div>
|
|
1850
|
+
<div class="card-content">
|
|
1851
|
+
<div class="card-title">{{ name }}</div>
|
|
1852
|
+
<div class="card-subtitle">{{ openclawSubtitle(config) }}</div>
|
|
1853
|
+
</div>
|
|
1854
|
+
</div>
|
|
1855
|
+
<div class="card-trailing">
|
|
1856
|
+
<span :class="['pill', openclawHasContent(config) ? 'configured' : 'empty']">
|
|
1857
|
+
{{ openclawHasContent(config) ? '已配置' : '未配置' }}
|
|
1858
|
+
</span>
|
|
1859
|
+
<div class="card-actions" @click.stop>
|
|
1860
|
+
<button class="card-action-btn" @click="openOpenclawEditModal(name)" title="编辑">
|
|
1861
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1862
|
+
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
1863
|
+
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
1864
|
+
</svg>
|
|
1865
|
+
</button>
|
|
1866
|
+
<button class="card-action-btn delete" @click="deleteOpenclawConfig(name)" title="删除">
|
|
1867
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
1868
|
+
<path d="M3 6h18"/>
|
|
1869
|
+
<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"/>
|
|
1870
|
+
</svg>
|
|
1871
|
+
</button>
|
|
1872
|
+
</div>
|
|
1873
|
+
</div>
|
|
1874
|
+
</div>
|
|
1875
|
+
</div>
|
|
1876
|
+
</div>
|
|
1877
|
+
|
|
1878
|
+
<!-- 会话浏览模式 -->
|
|
1879
|
+
<div v-show="configMode === 'sessions'" class="mode-content">
|
|
1819
1880
|
<div class="selector-section">
|
|
1820
1881
|
<div class="selector-header">
|
|
1821
1882
|
<span class="selector-title">会话来源</span>
|
|
@@ -2124,9 +2185,9 @@
|
|
|
2124
2185
|
</div>
|
|
2125
2186
|
|
|
2126
2187
|
<!-- 编辑Claude配置模态框 -->
|
|
2127
|
-
<div v-if="showEditConfigModal" class="modal-overlay" @click.self="closeEditConfigModal">
|
|
2128
|
-
<div class="modal">
|
|
2129
|
-
<div class="modal-title">编辑 Claude Code 配置</div>
|
|
2188
|
+
<div v-if="showEditConfigModal" class="modal-overlay" @click.self="closeEditConfigModal">
|
|
2189
|
+
<div class="modal">
|
|
2190
|
+
<div class="modal-title">编辑 Claude Code 配置</div>
|
|
2130
2191
|
|
|
2131
2192
|
<div class="form-group">
|
|
2132
2193
|
<label class="form-label">配置名称</label>
|
|
@@ -2150,13 +2211,61 @@
|
|
|
2150
2211
|
<button class="btn btn-confirm" @click="updateConfig">保存</button>
|
|
2151
2212
|
<button class="btn btn-confirm secondary" @click="saveAndApplyConfig">保存并应用到 Claude 配置</button>
|
|
2152
2213
|
<button class="btn btn-confirm secondary" @click="saveAndApplyEnvCompat">兼容模式应用到环境变量</button>
|
|
2153
|
-
</div>
|
|
2154
|
-
</div>
|
|
2155
|
-
</div>
|
|
2156
|
-
|
|
2157
|
-
<div v-if="
|
|
2158
|
-
<div class="modal modal-wide">
|
|
2159
|
-
<div class="modal-title">
|
|
2214
|
+
</div>
|
|
2215
|
+
</div>
|
|
2216
|
+
</div>
|
|
2217
|
+
|
|
2218
|
+
<div v-if="showOpenclawConfigModal" class="modal-overlay" @click.self="closeOpenclawConfigModal">
|
|
2219
|
+
<div class="modal modal-wide">
|
|
2220
|
+
<div class="modal-title">{{ openclawEditorTitle }}</div>
|
|
2221
|
+
|
|
2222
|
+
<div class="form-group">
|
|
2223
|
+
<label class="form-label">配置名称</label>
|
|
2224
|
+
<input v-model="openclawEditing.name" class="form-input" :readonly="openclawEditing.lockName" placeholder="例如: 默认配置">
|
|
2225
|
+
</div>
|
|
2226
|
+
|
|
2227
|
+
<div class="form-group">
|
|
2228
|
+
<label class="form-label">目标文件</label>
|
|
2229
|
+
<div class="form-hint">
|
|
2230
|
+
{{ openclawConfigPath || '未加载' }}
|
|
2231
|
+
<span v-if="openclawConfigPath">
|
|
2232
|
+
({{ openclawConfigExists ? '已存在' : '不存在,将在应用时创建' }})
|
|
2233
|
+
</span>
|
|
2234
|
+
</div>
|
|
2235
|
+
<div class="btn-group" style="justify-content:flex-start;">
|
|
2236
|
+
<button class="btn btn-confirm secondary" @click="loadOpenclawConfigFromFile" :disabled="openclawFileLoading">
|
|
2237
|
+
{{ openclawFileLoading ? '加载中...' : '加载当前配置' }}
|
|
2238
|
+
</button>
|
|
2239
|
+
</div>
|
|
2240
|
+
</div>
|
|
2241
|
+
|
|
2242
|
+
<div class="form-group">
|
|
2243
|
+
<label class="form-label">OpenClaw 配置(JSON5)</label>
|
|
2244
|
+
<textarea
|
|
2245
|
+
v-model="openclawEditing.content"
|
|
2246
|
+
class="form-input template-editor"
|
|
2247
|
+
spellcheck="false"
|
|
2248
|
+
placeholder="在这里编辑 OpenClaw 配置(JSON5)"></textarea>
|
|
2249
|
+
<div class="template-editor-warning">
|
|
2250
|
+
保存仅写入本地配置库;点击“保存并应用”后会写入 openclaw.json。
|
|
2251
|
+
</div>
|
|
2252
|
+
</div>
|
|
2253
|
+
|
|
2254
|
+
<div class="btn-group">
|
|
2255
|
+
<button class="btn btn-cancel" @click="closeOpenclawConfigModal">取消</button>
|
|
2256
|
+
<button class="btn btn-confirm" @click="saveOpenclawConfig" :disabled="openclawSaving">
|
|
2257
|
+
{{ openclawSaving ? '保存中...' : '保存' }}
|
|
2258
|
+
</button>
|
|
2259
|
+
<button class="btn btn-confirm secondary" @click="saveAndApplyOpenclawConfig" :disabled="openclawApplying">
|
|
2260
|
+
{{ openclawApplying ? '应用中...' : '保存并应用' }}
|
|
2261
|
+
</button>
|
|
2262
|
+
</div>
|
|
2263
|
+
</div>
|
|
2264
|
+
</div>
|
|
2265
|
+
|
|
2266
|
+
<div v-if="showConfigTemplateModal" class="modal-overlay" @click.self="closeConfigTemplateModal">
|
|
2267
|
+
<div class="modal modal-wide">
|
|
2268
|
+
<div class="modal-title">Config 模板编辑器(手动确认应用)</div>
|
|
2160
2269
|
|
|
2161
2270
|
<div class="form-group">
|
|
2162
2271
|
<label class="form-label">config.toml 模板</label>
|
|
@@ -2179,9 +2288,9 @@
|
|
|
2179
2288
|
</div>
|
|
2180
2289
|
</div>
|
|
2181
2290
|
|
|
2182
|
-
<div v-if="showAgentsModal" class="modal-overlay" @click.self="closeAgentsModal">
|
|
2183
|
-
<div class="modal modal-wide">
|
|
2184
|
-
<div class="modal-title">
|
|
2291
|
+
<div v-if="showAgentsModal" class="modal-overlay" @click.self="closeAgentsModal">
|
|
2292
|
+
<div class="modal modal-wide">
|
|
2293
|
+
<div class="modal-title">{{ agentsModalTitle }}</div>
|
|
2185
2294
|
|
|
2186
2295
|
<div class="form-group">
|
|
2187
2296
|
<label class="form-label">目标文件</label>
|
|
@@ -2195,16 +2304,16 @@
|
|
|
2195
2304
|
|
|
2196
2305
|
<div class="form-group">
|
|
2197
2306
|
<label class="form-label">AGENTS.md 内容</label>
|
|
2198
|
-
<textarea
|
|
2199
|
-
v-model="agentsContent"
|
|
2200
|
-
class="form-input template-editor"
|
|
2201
|
-
spellcheck="false"
|
|
2202
|
-
:readonly="agentsLoading"
|
|
2203
|
-
placeholder="在这里编辑 AGENTS.md 内容"></textarea>
|
|
2204
|
-
<div class="template-editor-warning">
|
|
2205
|
-
|
|
2206
|
-
</div>
|
|
2207
|
-
</div>
|
|
2307
|
+
<textarea
|
|
2308
|
+
v-model="agentsContent"
|
|
2309
|
+
class="form-input template-editor"
|
|
2310
|
+
spellcheck="false"
|
|
2311
|
+
:readonly="agentsLoading"
|
|
2312
|
+
placeholder="在这里编辑 AGENTS.md 内容"></textarea>
|
|
2313
|
+
<div class="template-editor-warning">
|
|
2314
|
+
{{ agentsModalHint }}
|
|
2315
|
+
</div>
|
|
2316
|
+
</div>
|
|
2208
2317
|
|
|
2209
2318
|
<div class="btn-group">
|
|
2210
2319
|
<button class="btn btn-cancel" @click="closeAgentsModal">取消</button>
|
|
@@ -2221,11 +2330,22 @@
|
|
|
2221
2330
|
<div v-if="message" :class="['toast', messageType]">{{ message }}</div>
|
|
2222
2331
|
</div>
|
|
2223
2332
|
|
|
2224
|
-
<script>
|
|
2225
|
-
const { createApp } = Vue;
|
|
2226
|
-
const API_BASE = 'http://localhost:3737';
|
|
2227
|
-
|
|
2228
|
-
|
|
2333
|
+
<script>
|
|
2334
|
+
const { createApp } = Vue;
|
|
2335
|
+
const API_BASE = 'http://localhost:3737';
|
|
2336
|
+
const DEFAULT_OPENCLAW_TEMPLATE = `{
|
|
2337
|
+
// OpenClaw config (JSON5)
|
|
2338
|
+
agent: {
|
|
2339
|
+
model: "gpt-4.1"
|
|
2340
|
+
},
|
|
2341
|
+
agents: {
|
|
2342
|
+
defaults: {
|
|
2343
|
+
workspace: "~/.openclaw/workspace"
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}`;
|
|
2347
|
+
|
|
2348
|
+
async function api(action, params = {}) {
|
|
2229
2349
|
const res = await fetch(`${API_BASE}/api`, {
|
|
2230
2350
|
method: 'POST',
|
|
2231
2351
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -2250,19 +2370,23 @@
|
|
|
2250
2370
|
showEditModal: false,
|
|
2251
2371
|
showModelModal: false,
|
|
2252
2372
|
showModelListModal: false,
|
|
2253
|
-
showClaudeConfigModal: false,
|
|
2254
|
-
showEditConfigModal: false,
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2373
|
+
showClaudeConfigModal: false,
|
|
2374
|
+
showEditConfigModal: false,
|
|
2375
|
+
showOpenclawConfigModal: false,
|
|
2376
|
+
showConfigTemplateModal: false,
|
|
2377
|
+
showAgentsModal: false,
|
|
2378
|
+
configTemplateContent: '',
|
|
2379
|
+
configTemplateApplying: false,
|
|
2380
|
+
agentsContent: '',
|
|
2381
|
+
agentsPath: '',
|
|
2382
|
+
agentsExists: false,
|
|
2383
|
+
agentsLineEnding: '\n',
|
|
2384
|
+
agentsLoading: false,
|
|
2385
|
+
agentsSaving: false,
|
|
2386
|
+
agentsContext: 'codex',
|
|
2387
|
+
agentsModalTitle: 'AGENTS.md 编辑器',
|
|
2388
|
+
agentsModalHint: '保存后会写入目标 AGENTS.md(与 config.toml 同级)。',
|
|
2389
|
+
sessionsList: [],
|
|
2266
2390
|
sessionsLoading: false,
|
|
2267
2391
|
sessionFilterSource: 'all',
|
|
2268
2392
|
sessionPathFilter: '',
|
|
@@ -2293,10 +2417,10 @@
|
|
|
2293
2417
|
speedLoading: {},
|
|
2294
2418
|
newProvider: { name: '', url: '', key: '' },
|
|
2295
2419
|
editingProvider: { name: '', url: '', key: '' },
|
|
2296
|
-
newModelName: '',
|
|
2297
|
-
currentClaudeConfig: '',
|
|
2298
|
-
editingConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
|
|
2299
|
-
claudeConfigs: {
|
|
2420
|
+
newModelName: '',
|
|
2421
|
+
currentClaudeConfig: '',
|
|
2422
|
+
editingConfig: { name: '', apiKey: '', baseUrl: '', model: '' },
|
|
2423
|
+
claudeConfigs: {
|
|
2300
2424
|
'智谱GLM': {
|
|
2301
2425
|
apiKey: '',
|
|
2302
2426
|
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
@@ -2304,19 +2428,33 @@
|
|
|
2304
2428
|
hasKey: false
|
|
2305
2429
|
}
|
|
2306
2430
|
},
|
|
2307
|
-
newClaudeConfig: {
|
|
2308
|
-
name: '',
|
|
2309
|
-
apiKey: '',
|
|
2310
|
-
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
2311
|
-
model: 'glm-4.7'
|
|
2312
|
-
}
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2431
|
+
newClaudeConfig: {
|
|
2432
|
+
name: '',
|
|
2433
|
+
apiKey: '',
|
|
2434
|
+
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
2435
|
+
model: 'glm-4.7'
|
|
2436
|
+
},
|
|
2437
|
+
currentOpenclawConfig: '',
|
|
2438
|
+
openclawConfigs: {
|
|
2439
|
+
'默认配置': {
|
|
2440
|
+
content: DEFAULT_OPENCLAW_TEMPLATE
|
|
2441
|
+
}
|
|
2442
|
+
},
|
|
2443
|
+
openclawEditing: { name: '', content: '', lockName: false },
|
|
2444
|
+
openclawEditorTitle: '添加 OpenClaw 配置',
|
|
2445
|
+
openclawConfigPath: '',
|
|
2446
|
+
openclawConfigExists: false,
|
|
2447
|
+
openclawLineEnding: '\n',
|
|
2448
|
+
openclawFileLoading: false,
|
|
2449
|
+
openclawSaving: false,
|
|
2450
|
+
openclawApplying: false
|
|
2451
|
+
}
|
|
2452
|
+
},
|
|
2453
|
+
mounted() {
|
|
2454
|
+
const savedConfigs = localStorage.getItem('claudeConfigs');
|
|
2455
|
+
if (savedConfigs) {
|
|
2456
|
+
try {
|
|
2457
|
+
this.claudeConfigs = JSON.parse(savedConfigs);
|
|
2320
2458
|
for (const [name, config] of Object.entries(this.claudeConfigs)) {
|
|
2321
2459
|
if (config.apiKey && config.apiKey.includes('****')) {
|
|
2322
2460
|
config.apiKey = '';
|
|
@@ -2331,10 +2469,27 @@
|
|
|
2331
2469
|
}
|
|
2332
2470
|
} catch (e) {
|
|
2333
2471
|
console.error('加载 Claude 配置失败:', e);
|
|
2334
|
-
}
|
|
2335
|
-
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
const savedOpenclawConfigs = localStorage.getItem('openclawConfigs');
|
|
2475
|
+
if (savedOpenclawConfigs) {
|
|
2476
|
+
try {
|
|
2477
|
+
this.openclawConfigs = JSON.parse(savedOpenclawConfigs);
|
|
2478
|
+
const configNames = Object.keys(this.openclawConfigs);
|
|
2479
|
+
if (configNames.length > 0) {
|
|
2480
|
+
this.currentOpenclawConfig = configNames[0];
|
|
2481
|
+
}
|
|
2482
|
+
} catch (e) {
|
|
2483
|
+
console.error('加载 OpenClaw 配置失败:', e);
|
|
2484
|
+
}
|
|
2485
|
+
} else {
|
|
2486
|
+
const configNames = Object.keys(this.openclawConfigs);
|
|
2487
|
+
if (configNames.length > 0) {
|
|
2488
|
+
this.currentOpenclawConfig = configNames[0];
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
this.loadAll();
|
|
2492
|
+
},
|
|
2338
2493
|
methods: {
|
|
2339
2494
|
async loadAll() {
|
|
2340
2495
|
this.loading = true;
|
|
@@ -2614,7 +2769,8 @@
|
|
|
2614
2769
|
pathFilter: this.sessionPathFilter,
|
|
2615
2770
|
query,
|
|
2616
2771
|
queryMode: 'and',
|
|
2617
|
-
queryScope: '
|
|
2772
|
+
queryScope: 'content',
|
|
2773
|
+
contentScanLimit: 2,
|
|
2618
2774
|
roleFilter: this.sessionRoleFilter,
|
|
2619
2775
|
timeRangePreset: this.sessionTimePreset,
|
|
2620
2776
|
limit: 200,
|
|
@@ -2828,44 +2984,84 @@
|
|
|
2828
2984
|
}
|
|
2829
2985
|
},
|
|
2830
2986
|
|
|
2831
|
-
async openAgentsEditor() {
|
|
2832
|
-
this.
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2987
|
+
async openAgentsEditor() {
|
|
2988
|
+
this.setAgentsModalContext('codex');
|
|
2989
|
+
this.agentsLoading = true;
|
|
2990
|
+
try {
|
|
2991
|
+
const res = await api('get-agents-file');
|
|
2992
|
+
if (res.error) {
|
|
2993
|
+
this.showMessage(res.error, 'error');
|
|
2837
2994
|
return;
|
|
2838
2995
|
}
|
|
2839
2996
|
this.agentsContent = res.content || '';
|
|
2840
2997
|
this.agentsPath = res.path || '';
|
|
2841
2998
|
this.agentsExists = !!res.exists;
|
|
2842
|
-
this.agentsLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
2843
|
-
this.showAgentsModal = true;
|
|
2844
|
-
} catch (e) {
|
|
2845
|
-
this.showMessage('加载 AGENTS.md 失败: ' + e.message, 'error');
|
|
2846
|
-
} finally {
|
|
2847
|
-
this.agentsLoading = false;
|
|
2848
|
-
}
|
|
2849
|
-
},
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
this.
|
|
2853
|
-
this.
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2999
|
+
this.agentsLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
3000
|
+
this.showAgentsModal = true;
|
|
3001
|
+
} catch (e) {
|
|
3002
|
+
this.showMessage('加载 AGENTS.md 失败: ' + e.message, 'error');
|
|
3003
|
+
} finally {
|
|
3004
|
+
this.agentsLoading = false;
|
|
3005
|
+
}
|
|
3006
|
+
},
|
|
3007
|
+
|
|
3008
|
+
async openOpenclawAgentsEditor() {
|
|
3009
|
+
this.setAgentsModalContext('openclaw');
|
|
3010
|
+
this.agentsLoading = true;
|
|
3011
|
+
try {
|
|
3012
|
+
const res = await api('get-openclaw-agents-file');
|
|
3013
|
+
if (res.error) {
|
|
3014
|
+
this.showMessage(res.error, 'error');
|
|
3015
|
+
return;
|
|
3016
|
+
}
|
|
3017
|
+
if (res.configError) {
|
|
3018
|
+
this.showMessage(`OpenClaw 配置解析失败,已使用默认 Workspace:${res.configError}`, 'error');
|
|
3019
|
+
}
|
|
3020
|
+
this.agentsContent = res.content || '';
|
|
3021
|
+
this.agentsPath = res.path || '';
|
|
3022
|
+
this.agentsExists = !!res.exists;
|
|
3023
|
+
this.agentsLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
3024
|
+
this.showAgentsModal = true;
|
|
3025
|
+
} catch (e) {
|
|
3026
|
+
this.showMessage('加载 OpenClaw AGENTS.md 失败: ' + e.message, 'error');
|
|
3027
|
+
} finally {
|
|
3028
|
+
this.agentsLoading = false;
|
|
3029
|
+
}
|
|
3030
|
+
},
|
|
3031
|
+
|
|
3032
|
+
setAgentsModalContext(context) {
|
|
3033
|
+
this.agentsContext = context === 'openclaw' ? 'openclaw' : 'codex';
|
|
3034
|
+
if (this.agentsContext === 'openclaw') {
|
|
3035
|
+
this.agentsModalTitle = 'OpenClaw AGENTS.md 编辑器';
|
|
3036
|
+
this.agentsModalHint = '保存后会写入 OpenClaw Workspace 下的 AGENTS.md。';
|
|
3037
|
+
} else {
|
|
3038
|
+
this.agentsModalTitle = 'AGENTS.md 编辑器';
|
|
3039
|
+
this.agentsModalHint = '保存后会写入目标 AGENTS.md(与 config.toml 同级)。';
|
|
3040
|
+
}
|
|
3041
|
+
},
|
|
3042
|
+
|
|
3043
|
+
closeAgentsModal() {
|
|
3044
|
+
this.showAgentsModal = false;
|
|
3045
|
+
this.agentsContent = '';
|
|
3046
|
+
this.agentsPath = '';
|
|
3047
|
+
this.agentsExists = false;
|
|
3048
|
+
this.agentsLineEnding = '\n';
|
|
3049
|
+
this.agentsSaving = false;
|
|
3050
|
+
this.setAgentsModalContext('codex');
|
|
3051
|
+
},
|
|
3052
|
+
|
|
3053
|
+
async applyAgentsContent() {
|
|
3054
|
+
this.agentsSaving = true;
|
|
3055
|
+
try {
|
|
3056
|
+
const action = this.agentsContext === 'openclaw'
|
|
3057
|
+
? 'apply-openclaw-agents-file'
|
|
3058
|
+
: 'apply-agents-file';
|
|
3059
|
+
const res = await api(action, {
|
|
3060
|
+
content: this.agentsContent,
|
|
3061
|
+
lineEnding: this.agentsLineEnding
|
|
3062
|
+
});
|
|
3063
|
+
if (res.error) {
|
|
3064
|
+
this.showMessage(res.error, 'error');
|
|
2869
3065
|
return;
|
|
2870
3066
|
}
|
|
2871
3067
|
this.showMessage('AGENTS.md 已保存', 'success');
|
|
@@ -3128,20 +3324,187 @@
|
|
|
3128
3324
|
}
|
|
3129
3325
|
},
|
|
3130
3326
|
|
|
3131
|
-
closeClaudeConfigModal() {
|
|
3132
|
-
this.showClaudeConfigModal = false;
|
|
3133
|
-
this.newClaudeConfig = {
|
|
3134
|
-
name: '',
|
|
3135
|
-
apiKey: '',
|
|
3136
|
-
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
3137
|
-
model: 'glm-4.7'
|
|
3138
|
-
};
|
|
3139
|
-
},
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3327
|
+
closeClaudeConfigModal() {
|
|
3328
|
+
this.showClaudeConfigModal = false;
|
|
3329
|
+
this.newClaudeConfig = {
|
|
3330
|
+
name: '',
|
|
3331
|
+
apiKey: '',
|
|
3332
|
+
baseUrl: 'https://open.bigmodel.cn/api/anthropic',
|
|
3333
|
+
model: 'glm-4.7'
|
|
3334
|
+
};
|
|
3335
|
+
},
|
|
3336
|
+
|
|
3337
|
+
openclawHasContent(config) {
|
|
3338
|
+
return !!(config && typeof config.content === 'string' && config.content.trim());
|
|
3339
|
+
},
|
|
3340
|
+
|
|
3341
|
+
openclawSubtitle(config) {
|
|
3342
|
+
if (!this.openclawHasContent(config)) {
|
|
3343
|
+
return '未设置配置';
|
|
3344
|
+
}
|
|
3345
|
+
const length = config.content.trim().length;
|
|
3346
|
+
return `已保存 ${length} 字符`;
|
|
3347
|
+
},
|
|
3348
|
+
|
|
3349
|
+
saveOpenclawConfigs() {
|
|
3350
|
+
localStorage.setItem('openclawConfigs', JSON.stringify(this.openclawConfigs));
|
|
3351
|
+
},
|
|
3352
|
+
|
|
3353
|
+
openOpenclawAddModal() {
|
|
3354
|
+
this.openclawEditorTitle = '添加 OpenClaw 配置';
|
|
3355
|
+
this.openclawEditing = {
|
|
3356
|
+
name: '',
|
|
3357
|
+
content: DEFAULT_OPENCLAW_TEMPLATE,
|
|
3358
|
+
lockName: false
|
|
3359
|
+
};
|
|
3360
|
+
this.openclawConfigPath = '';
|
|
3361
|
+
this.openclawConfigExists = false;
|
|
3362
|
+
this.openclawLineEnding = '\n';
|
|
3363
|
+
this.showOpenclawConfigModal = true;
|
|
3364
|
+
},
|
|
3365
|
+
|
|
3366
|
+
openOpenclawEditModal(name) {
|
|
3367
|
+
const config = this.openclawConfigs[name];
|
|
3368
|
+
this.openclawEditorTitle = `编辑 OpenClaw 配置: ${name}`;
|
|
3369
|
+
this.openclawEditing = {
|
|
3370
|
+
name,
|
|
3371
|
+
content: (config && config.content) ? config.content : '',
|
|
3372
|
+
lockName: true
|
|
3373
|
+
};
|
|
3374
|
+
this.showOpenclawConfigModal = true;
|
|
3375
|
+
},
|
|
3376
|
+
|
|
3377
|
+
closeOpenclawConfigModal() {
|
|
3378
|
+
this.showOpenclawConfigModal = false;
|
|
3379
|
+
this.openclawEditing = { name: '', content: '', lockName: false };
|
|
3380
|
+
this.openclawSaving = false;
|
|
3381
|
+
this.openclawApplying = false;
|
|
3382
|
+
},
|
|
3383
|
+
|
|
3384
|
+
async loadOpenclawConfigFromFile() {
|
|
3385
|
+
this.openclawFileLoading = true;
|
|
3386
|
+
try {
|
|
3387
|
+
const res = await api('get-openclaw-config');
|
|
3388
|
+
if (res.error) {
|
|
3389
|
+
this.showMessage(res.error, 'error');
|
|
3390
|
+
return;
|
|
3391
|
+
}
|
|
3392
|
+
this.openclawConfigPath = res.path || '';
|
|
3393
|
+
this.openclawConfigExists = !!res.exists;
|
|
3394
|
+
this.openclawLineEnding = res.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
3395
|
+
if (res.content && res.content.trim()) {
|
|
3396
|
+
this.openclawEditing.content = res.content;
|
|
3397
|
+
} else if (!this.openclawEditing.content) {
|
|
3398
|
+
this.openclawEditing.content = DEFAULT_OPENCLAW_TEMPLATE;
|
|
3399
|
+
}
|
|
3400
|
+
this.showMessage('已加载当前 OpenClaw 配置', 'success');
|
|
3401
|
+
} catch (e) {
|
|
3402
|
+
this.showMessage('加载 OpenClaw 配置失败: ' + e.message, 'error');
|
|
3403
|
+
} finally {
|
|
3404
|
+
this.openclawFileLoading = false;
|
|
3405
|
+
}
|
|
3406
|
+
},
|
|
3407
|
+
|
|
3408
|
+
persistOpenclawConfig({ closeModal = true } = {}) {
|
|
3409
|
+
if (!this.openclawEditing.name || !this.openclawEditing.name.trim()) {
|
|
3410
|
+
this.showMessage('请输入配置名称', 'error');
|
|
3411
|
+
return '';
|
|
3412
|
+
}
|
|
3413
|
+
const name = this.openclawEditing.name.trim();
|
|
3414
|
+
if (!this.openclawEditing.lockName && this.openclawConfigs[name]) {
|
|
3415
|
+
this.showMessage('配置名称已存在', 'error');
|
|
3416
|
+
return '';
|
|
3417
|
+
}
|
|
3418
|
+
if (!this.openclawEditing.content || !this.openclawEditing.content.trim()) {
|
|
3419
|
+
this.showMessage('配置内容不能为空', 'error');
|
|
3420
|
+
return '';
|
|
3421
|
+
}
|
|
3422
|
+
|
|
3423
|
+
this.openclawConfigs[name] = {
|
|
3424
|
+
content: this.openclawEditing.content
|
|
3425
|
+
};
|
|
3426
|
+
this.currentOpenclawConfig = name;
|
|
3427
|
+
this.saveOpenclawConfigs();
|
|
3428
|
+
if (closeModal) {
|
|
3429
|
+
this.closeOpenclawConfigModal();
|
|
3430
|
+
}
|
|
3431
|
+
return name;
|
|
3432
|
+
},
|
|
3433
|
+
|
|
3434
|
+
async saveOpenclawConfig() {
|
|
3435
|
+
this.openclawSaving = true;
|
|
3436
|
+
try {
|
|
3437
|
+
const name = this.persistOpenclawConfig();
|
|
3438
|
+
if (!name) return;
|
|
3439
|
+
this.showMessage('OpenClaw 配置已保存', 'success');
|
|
3440
|
+
} finally {
|
|
3441
|
+
this.openclawSaving = false;
|
|
3442
|
+
}
|
|
3443
|
+
},
|
|
3444
|
+
|
|
3445
|
+
async saveAndApplyOpenclawConfig() {
|
|
3446
|
+
this.openclawApplying = true;
|
|
3447
|
+
try {
|
|
3448
|
+
const name = this.persistOpenclawConfig({ closeModal: false });
|
|
3449
|
+
if (!name) return;
|
|
3450
|
+
const config = this.openclawConfigs[name];
|
|
3451
|
+
const res = await api('apply-openclaw-config', {
|
|
3452
|
+
content: config.content,
|
|
3453
|
+
lineEnding: this.openclawLineEnding
|
|
3454
|
+
});
|
|
3455
|
+
if (res.error || res.success === false) {
|
|
3456
|
+
this.showMessage(res.error || '应用 OpenClaw 配置失败', 'error');
|
|
3457
|
+
return;
|
|
3458
|
+
}
|
|
3459
|
+
this.openclawConfigPath = res.targetPath || this.openclawConfigPath;
|
|
3460
|
+
this.openclawConfigExists = true;
|
|
3461
|
+
const targetTip = res.targetPath ? `(${res.targetPath})` : '';
|
|
3462
|
+
this.showMessage(`已保存并应用 OpenClaw 配置${targetTip}`, 'success');
|
|
3463
|
+
this.closeOpenclawConfigModal();
|
|
3464
|
+
} catch (e) {
|
|
3465
|
+
this.showMessage('应用 OpenClaw 配置失败: ' + e.message, 'error');
|
|
3466
|
+
} finally {
|
|
3467
|
+
this.openclawApplying = false;
|
|
3468
|
+
}
|
|
3469
|
+
},
|
|
3470
|
+
|
|
3471
|
+
deleteOpenclawConfig(name) {
|
|
3472
|
+
if (Object.keys(this.openclawConfigs).length <= 1) {
|
|
3473
|
+
return this.showMessage('至少保留一个配置', 'error');
|
|
3474
|
+
}
|
|
3475
|
+
if (!confirm(`确定删除配置 "${name}"?`)) return;
|
|
3476
|
+
delete this.openclawConfigs[name];
|
|
3477
|
+
if (this.currentOpenclawConfig === name) {
|
|
3478
|
+
this.currentOpenclawConfig = Object.keys(this.openclawConfigs)[0];
|
|
3479
|
+
}
|
|
3480
|
+
this.saveOpenclawConfigs();
|
|
3481
|
+
this.showMessage('OpenClaw 配置已删除', 'success');
|
|
3482
|
+
},
|
|
3483
|
+
|
|
3484
|
+
async applyOpenclawConfig(name) {
|
|
3485
|
+
this.currentOpenclawConfig = name;
|
|
3486
|
+
const config = this.openclawConfigs[name];
|
|
3487
|
+
if (!this.openclawHasContent(config)) {
|
|
3488
|
+
return this.showMessage('该配置为空,请先编辑', 'error');
|
|
3489
|
+
}
|
|
3490
|
+
const res = await api('apply-openclaw-config', {
|
|
3491
|
+
content: config.content,
|
|
3492
|
+
lineEnding: this.openclawLineEnding
|
|
3493
|
+
});
|
|
3494
|
+
if (res.error || res.success === false) {
|
|
3495
|
+
this.showMessage(res.error || '应用 OpenClaw 配置失败', 'error');
|
|
3496
|
+
} else {
|
|
3497
|
+
this.openclawConfigPath = res.targetPath || this.openclawConfigPath;
|
|
3498
|
+
this.openclawConfigExists = true;
|
|
3499
|
+
const targetTip = res.targetPath ? `(${res.targetPath})` : '';
|
|
3500
|
+
this.showMessage(`已应用 OpenClaw 配置: ${name}${targetTip}`, 'success');
|
|
3501
|
+
}
|
|
3502
|
+
},
|
|
3503
|
+
|
|
3504
|
+
formatLatency(result) {
|
|
3505
|
+
if (!result) return '';
|
|
3506
|
+
if (!result.ok) return result.status ? `ERR ${result.status}` : 'ERR';
|
|
3507
|
+
const ms = typeof result.durationMs === 'number' ? result.durationMs : 0;
|
|
3145
3508
|
return `${ms}ms`;
|
|
3146
3509
|
},
|
|
3147
3510
|
|