codexmate 0.0.20 → 0.0.22

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.
Files changed (96) hide show
  1. package/README.md +289 -152
  2. package/README.zh.md +321 -0
  3. package/cli/agents-files.js +224 -0
  4. package/cli/archive-helpers.js +446 -0
  5. package/cli/auth-profiles.js +359 -0
  6. package/cli/builtin-proxy.js +1044 -0
  7. package/cli/claude-proxy.js +998 -0
  8. package/cli/config-bootstrap.js +384 -0
  9. package/cli/openai-bridge.js +950 -0
  10. package/cli/openclaw-config.js +629 -0
  11. package/cli/session-usage.concurrent.js +28 -0
  12. package/cli/session-usage.js +112 -0
  13. package/cli/session-usage.models.js +176 -0
  14. package/cli/skills.js +1141 -0
  15. package/cli/zip-commands.js +510 -0
  16. package/cli.js +9408 -9719
  17. package/lib/cli-models-utils.js +109 -1
  18. package/lib/cli-path-utils.js +69 -0
  19. package/lib/cli-sessions.js +386 -0
  20. package/lib/download-artifacts.js +77 -0
  21. package/lib/task-orchestrator.js +869 -0
  22. package/package.json +14 -10
  23. package/res/logo.png +0 -0
  24. package/res/vue.global.prod.js +13 -0
  25. package/web-ui/app.js +193 -15
  26. package/web-ui/index.html +5 -1
  27. package/web-ui/logic.agents-diff.mjs +1 -1
  28. package/web-ui/logic.claude.mjs +60 -0
  29. package/web-ui/logic.runtime.mjs +11 -7
  30. package/web-ui/logic.sessions.mjs +372 -21
  31. package/web-ui/modules/api.mjs +22 -1
  32. package/web-ui/modules/app.computed.dashboard.mjs +23 -10
  33. package/web-ui/modules/app.computed.index.mjs +4 -0
  34. package/web-ui/modules/app.computed.main-tabs.mjs +198 -0
  35. package/web-ui/modules/app.computed.session.mjs +521 -9
  36. package/web-ui/modules/app.methods.agents.mjs +62 -11
  37. package/web-ui/modules/app.methods.codex-config.mjs +189 -34
  38. package/web-ui/modules/app.methods.index.mjs +7 -1
  39. package/web-ui/modules/app.methods.install.mjs +24 -20
  40. package/web-ui/modules/app.methods.navigation.mjs +142 -1
  41. package/web-ui/modules/app.methods.openclaw-core.mjs +339 -39
  42. package/web-ui/modules/app.methods.openclaw-editing.mjs +39 -4
  43. package/web-ui/modules/app.methods.openclaw-persist.mjs +122 -4
  44. package/web-ui/modules/app.methods.providers.mjs +192 -53
  45. package/web-ui/modules/app.methods.session-actions.mjs +99 -19
  46. package/web-ui/modules/app.methods.session-browser.mjs +196 -5
  47. package/web-ui/modules/app.methods.session-timeline.mjs +22 -15
  48. package/web-ui/modules/app.methods.session-trash.mjs +3 -0
  49. package/web-ui/modules/app.methods.startup-claude.mjs +70 -71
  50. package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
  51. package/web-ui/modules/config-mode.computed.mjs +2 -0
  52. package/web-ui/modules/config-template-confirm-pref.mjs +33 -0
  53. package/web-ui/modules/i18n.mjs +1609 -0
  54. package/web-ui/modules/plugins.computed.mjs +220 -0
  55. package/web-ui/modules/plugins.methods.mjs +620 -0
  56. package/web-ui/modules/plugins.storage.mjs +37 -0
  57. package/web-ui/partials/index/layout-footer.html +1 -57
  58. package/web-ui/partials/index/layout-header.html +299 -175
  59. package/web-ui/partials/index/modal-config-template-agents.html +79 -29
  60. package/web-ui/partials/index/modal-confirm-toast.html +1 -1
  61. package/web-ui/partials/index/modal-health-check.html +14 -14
  62. package/web-ui/partials/index/modal-openclaw-config.html +47 -42
  63. package/web-ui/partials/index/modal-skills.html +130 -114
  64. package/web-ui/partials/index/modals-basic.html +71 -102
  65. package/web-ui/partials/index/panel-config-claude.html +50 -12
  66. package/web-ui/partials/index/panel-config-codex.html +34 -37
  67. package/web-ui/partials/index/panel-config-openclaw.html +10 -16
  68. package/web-ui/partials/index/panel-docs.html +147 -0
  69. package/web-ui/partials/index/panel-market.html +38 -38
  70. package/web-ui/partials/index/panel-orchestration.html +397 -0
  71. package/web-ui/partials/index/panel-plugins.html +243 -0
  72. package/web-ui/partials/index/panel-sessions.html +51 -146
  73. package/web-ui/partials/index/panel-settings.html +188 -96
  74. package/web-ui/partials/index/panel-usage.html +353 -0
  75. package/web-ui/session-helpers.mjs +221 -10
  76. package/web-ui/styles/base-theme.css +120 -229
  77. package/web-ui/styles/controls-forms.css +59 -51
  78. package/web-ui/styles/docs-panel.css +247 -0
  79. package/web-ui/styles/layout-shell.css +394 -128
  80. package/web-ui/styles/modals-core.css +18 -3
  81. package/web-ui/styles/navigation-panels.css +184 -183
  82. package/web-ui/styles/plugins-panel.css +518 -0
  83. package/web-ui/styles/responsive.css +102 -62
  84. package/web-ui/styles/sessions-list.css +13 -27
  85. package/web-ui/styles/sessions-preview.css +13 -7
  86. package/web-ui/styles/sessions-toolbar-trash.css +25 -0
  87. package/web-ui/styles/sessions-usage.css +581 -6
  88. package/web-ui/styles/settings-panel.css +166 -0
  89. package/web-ui/styles/skills-list.css +16 -11
  90. package/web-ui/styles/skills-market.css +63 -2
  91. package/web-ui/styles/task-orchestration.css +776 -0
  92. package/web-ui/styles/titles-cards.css +67 -66
  93. package/web-ui/styles.css +4 -0
  94. package/README.en.md +0 -259
  95. package/res/screenshot.png +0 -0
  96. package/res/vue.global.js +0 -18552
@@ -10,15 +10,41 @@
10
10
  <svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
11
11
  <path d="M10 4v12M4 10h12"/>
12
12
  </svg>
13
- 添加提供商
13
+ {{ t('claude.addProvider') }}
14
14
  </button>
15
15
  <div class="config-template-hint">
16
- 默认应用到 <code>~/.claude/settings.json</code>。
16
+ {{ t('claude.applyDefault') }}
17
17
  </div>
18
18
 
19
19
  <div class="selector-section">
20
20
  <div class="selector-header">
21
- <span class="selector-title">模型</span>
21
+ <span class="selector-title">{{ t('claude.presetProviders') }}</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">{{ t('claude.customConfig') }}</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">{{ t('claude.model') }}</span>
22
48
  </div>
23
49
  <select
24
50
  v-if="claudeModelHasList"
@@ -34,20 +60,32 @@
34
60
  v-model="currentClaudeModel"
35
61
  @blur="onClaudeModelChange"
36
62
  @keyup.enter="onClaudeModelChange"
37
- placeholder="例如: claude-3-7-sonnet"
63
+ :placeholder="t('claude.model.placeholder')"
38
64
  >
39
65
  <div class="config-template-hint">
40
- 模型修改后会自动保存并应用到当前配置。
66
+ {{ t('claude.model.hint') }}
41
67
  </div>
42
68
  </div>
43
69
 
44
70
  <div class="selector-section">
45
71
  <div class="selector-header">
46
- <span class="selector-title">配置健康检查</span>
72
+ <span class="selector-title">{{ t('claude.health.title') }}</span>
47
73
  </div>
48
74
  <button class="btn-tool" @click="runHealthCheck" :disabled="healthCheckLoading || loading || !!initError">
49
- {{ healthCheckLoading ? '检查中...' : '运行检查' }}
75
+ {{ healthCheckLoading ? t('claude.health.running') : t('claude.health.run') }}
76
+ </button>
77
+ </div>
78
+
79
+ <div class="selector-section">
80
+ <div class="selector-header">
81
+ <span class="selector-title">CLAUDE.md</span>
82
+ </div>
83
+ <button class="btn-tool" @click="openClaudeMdEditor" :disabled="loading || !!initError || agentsLoading">
84
+ {{ agentsLoading ? t('config.modelLoading') : t('claude.md.open') }}
50
85
  </button>
86
+ <div class="config-template-hint">
87
+ {{ t('claude.md.hint') }}
88
+ </div>
51
89
  </div>
52
90
 
53
91
  <div class="card-list">
@@ -63,31 +101,31 @@
63
101
  <div class="card-icon">{{ name.charAt(0).toUpperCase() }}</div>
64
102
  <div class="card-content">
65
103
  <div class="card-title">{{ name }}</div>
66
- <div class="card-subtitle">{{ config.model || '未设置模型' }}</div>
104
+ <div class="card-subtitle">{{ config.model || t('claude.model.unset') }}</div>
67
105
  </div>
68
106
  </div>
69
107
  <div class="card-trailing">
70
108
  <span :class="['pill', config.hasKey ? 'configured' : 'empty']">
71
- {{ config.hasKey ? '已配置' : '未配置' }}
109
+ {{ config.hasKey ? t('claude.configured') : t('claude.notConfigured') }}
72
110
  </span>
73
111
  <span v-if="claudeSpeedResults[name]" :class="['latency', claudeSpeedResults[name].ok ? 'ok' : 'error']">
74
112
  {{ formatLatency(claudeSpeedResults[name]) }}
75
113
  </span>
76
114
  <div class="card-actions" @click.stop>
77
- <button class="card-action-btn" @click="openEditConfigModal(name)" :aria-label="`Edit Claude config ${name}`" title="编辑">
115
+ <button class="card-action-btn" @click="openEditConfigModal(name)" :aria-label="`Edit Claude config ${name}`" :title="t('claude.action.edit')">
78
116
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
79
117
  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
80
118
  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
81
119
  </svg>
82
120
  </button>
83
- <button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled title="分享导入命令(暂时禁用)" aria-label="Share import command">
121
+ <button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled :title="t('claude.action.shareDisabled')" aria-label="Share import command">
84
122
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
85
123
  <path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
86
124
  <path d="M16 6l-4-4-4 4"/>
87
125
  <path d="M12 2v14"/>
88
126
  </svg>
89
127
  </button>
90
- <button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="`Delete Claude config ${name}`" title="删除">
128
+ <button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="`Delete Claude config ${name}`" :title="t('claude.action.delete')">
91
129
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
92
130
  <path d="M3 6h18"/>
93
131
  <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"/>
@@ -10,13 +10,13 @@
10
10
  <svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
11
11
  <path d="M10 4v12M4 10h12"/>
12
12
  </svg>
13
- 新增提供商
13
+ {{ t('config.addProvider') }}
14
14
  </button>
15
15
 
16
16
  <!-- 模型选择器 -->
17
17
  <div class="selector-section">
18
18
  <div class="selector-header">
19
- <span class="selector-title">模型</span>
19
+ <span class="selector-title">{{ t('config.models') }}</span>
20
20
  <div class="selector-actions">
21
21
  <button class="btn-icon" @click="showModelModal = true" aria-label="Add model" title="添加模型" v-if="modelsSource === 'legacy'">+</button>
22
22
  <button class="btn-icon" @click="showModelListModal = true" aria-label="Manage models" title="管理模型" v-if="modelsSource === 'legacy'">≡</button>
@@ -29,7 +29,7 @@
29
29
  @change="onModelChange"
30
30
  :disabled="codexModelsLoading"
31
31
  >
32
- <option v-if="codexModelsLoading" value="">加载中...</option>
32
+ <option v-if="codexModelsLoading" value="">{{ t('config.modelLoading') }}</option>
33
33
  <option v-else v-for="model in models" :key="model" :value="model">{{ model }}</option>
34
34
  </select>
35
35
  <input
@@ -40,63 +40,63 @@
40
40
  :placeholder="activeProviderModelPlaceholder"
41
41
  >
42
42
  <div class="config-template-hint" v-if="modelsSource === 'unlimited'">
43
- 当前无模型列表,可手填。
43
+ {{ t('config.models.unlimited') }}
44
44
  </div>
45
45
  <div class="config-template-hint" v-if="modelsSource === 'error'">
46
- 模型列表获取失败,可手填。
46
+ {{ t('config.models.error') }}
47
47
  </div>
48
48
  <div class="config-template-hint" v-if="modelsSource === 'remote' && !modelsHasCurrent">
49
- {{ isCodexConfigMode ? '当前模型不在列表,可手填或改模板。' : '当前模型不在列表,可手填。' }}
49
+ {{ isCodexConfigMode ? t('config.models.notInList.codex') : t('config.models.notInList.other') }}
50
50
  </div>
51
51
  <div class="config-template-hint" v-if="isCodexConfigMode">
52
- 先改模板,再应用。
52
+ {{ t('config.template.editFirst') }}
53
53
  </div>
54
54
  <div class="config-template-hint" v-else-if="activeProviderBridgeHint">
55
- {{ activeProviderBridgeHint }} 模板仅限 Codex 编辑。
55
+ {{ t('config.template.bridgeCodexOnly', { hint: activeProviderBridgeHint }) }}
56
56
  </div>
57
57
  <button class="btn-tool btn-template-editor" v-if="isCodexConfigMode" @click="openConfigTemplateEditor" :disabled="loading || !!initError">
58
- 打开模板编辑器
58
+ {{ t('config.template.openEditor') }}
59
59
  </button>
60
60
  </div>
61
61
 
62
62
  <template v-if="isCodexConfigMode">
63
63
  <div class="selector-section">
64
64
  <div class="selector-header">
65
- <span class="selector-title">服务档</span>
65
+ <span class="selector-title">{{ t('config.serviceTier') }}</span>
66
66
  </div>
67
67
  <select class="model-select" v-model="serviceTier" @change="onServiceTierChange">
68
- <option value="fast">fast(默认)</option>
68
+ <option value="fast">{{ t('config.serviceTier.fast') }}</option>
69
69
  <option value="standard">standard</option>
70
70
  </select>
71
71
  <div class="config-template-hint">
72
- fast 写入 <code>service_tier</code>。
72
+ {{ t('config.serviceTier.hint', { field: 'service_tier' }) }}
73
73
  </div>
74
74
  </div>
75
75
 
76
76
  <div class="selector-section">
77
77
  <div class="selector-header">
78
- <span class="selector-title">推理强度</span>
78
+ <span class="selector-title">{{ t('config.reasoningEffort') }}</span>
79
79
  </div>
80
80
  <select class="model-select" v-model="modelReasoningEffort" @change="onReasoningEffortChange">
81
81
  <option value="high">high</option>
82
- <option value="medium">medium(默认)</option>
82
+ <option value="medium">{{ t('config.reasoningEffort.medium') }}</option>
83
83
  <option value="low">low</option>
84
84
  <option value="xhigh">xhigh</option>
85
85
  </select>
86
86
  <div class="config-template-hint">
87
- 控制推理深度;high 更深。
87
+ {{ t('config.reasoningEffort.hint') }}
88
88
  </div>
89
89
  </div>
90
90
 
91
91
  <div class="selector-section">
92
92
  <div class="selector-header">
93
- <span class="selector-title">压缩阈值</span>
93
+ <span class="selector-title">{{ t('config.contextBudget') }}</span>
94
94
  <div class="selector-actions">
95
95
  <button
96
96
  class="btn-tool btn-tool-compact"
97
97
  @click="resetCodexContextBudgetDefaults"
98
98
  :disabled="loading || !!initError || codexApplying">
99
- 重置
99
+ {{ t('config.reset') }}
100
100
  </button>
101
101
  </div>
102
102
  </div>
@@ -109,12 +109,12 @@
109
109
  class="form-input"
110
110
  inputmode="numeric"
111
111
  autocomplete="off"
112
- placeholder="例如: 190000"
112
+ :placeholder="t('config.example', { value: 190000 })"
113
113
  @focus="editingCodexBudgetField = 'modelContextWindowInput'"
114
114
  @input="sanitizePositiveIntegerDraft('modelContextWindowInput')"
115
115
  @blur="onModelContextWindowBlur"
116
116
  @keydown.enter.prevent="onModelContextWindowBlur">
117
- <div class="form-hint">上下文上限,默认 190000。</div>
117
+ <div class="form-hint">{{ t('config.contextWindow.hint') }}</div>
118
118
  </div>
119
119
  <div class="form-group codex-config-field">
120
120
  <label class="form-label" for="codex-model-auto-compact-token-limit">model_auto_compact_token_limit</label>
@@ -124,12 +124,12 @@
124
124
  class="form-input"
125
125
  inputmode="numeric"
126
126
  autocomplete="off"
127
- placeholder="例如: 185000"
127
+ :placeholder="t('config.example', { value: 185000 })"
128
128
  @focus="editingCodexBudgetField = 'modelAutoCompactTokenLimitInput'"
129
129
  @input="sanitizePositiveIntegerDraft('modelAutoCompactTokenLimitInput')"
130
130
  @blur="onModelAutoCompactTokenLimitBlur"
131
131
  @keydown.enter.prevent="onModelAutoCompactTokenLimitBlur">
132
- <div class="form-hint">自动压缩阈值,默认 185000。</div>
132
+ <div class="form-hint">{{ t('config.autoCompact.hint') }}</div>
133
133
  </div>
134
134
  </div>
135
135
  </div>
@@ -139,21 +139,12 @@
139
139
  <span class="selector-title">AGENTS.md</span>
140
140
  </div>
141
141
  <button class="btn-tool" @click="openAgentsEditor" :disabled="loading || !!initError || agentsLoading">
142
- {{ agentsLoading ? '加载中...' : '打开 AGENTS.md' }}
142
+ {{ agentsLoading ? t('config.modelLoading') : t('config.agents.open') }}
143
143
  </button>
144
144
  </div>
145
145
 
146
146
  </template>
147
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
148
  <div v-if="!loading && !initError" class="card-list">
158
149
  <div v-for="provider in displayProvidersList" :key="provider.name"
159
150
  :class="['card', { active: displayCurrentProvider === provider.name }]"
@@ -168,10 +159,10 @@
168
159
  <div class="card-content">
169
160
  <div class="card-title">
170
161
  <span>{{ provider.name }}</span>
171
- <span v-if="provider.readOnly" class="provider-readonly-badge">系统</span>
162
+ <span v-if="provider.readOnly" class="provider-readonly-badge">{{ t('config.badge.system') }}</span>
172
163
  </div>
173
164
  <div class="card-subtitle">
174
- {{ provider.url || '未设 URL' }}
165
+ {{ provider.url || t('config.url.unset') }}
175
166
  </div>
176
167
  </div>
177
168
  </div>
@@ -183,7 +174,13 @@
183
174
  {{ formatLatency(speedResults[provider.name]) }}
184
175
  </span>
185
176
  <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="检测对话">
177
+ <button
178
+ class="card-action-btn"
179
+ @click="openHealthCheckDialog({ providerName: provider.name, locked: true })"
180
+ :disabled="displayCurrentProvider !== provider.name"
181
+ :aria-label="`Open health dialog for ${provider.name}`"
182
+ :title="displayCurrentProvider === provider.name ? t('config.healthTest') : t('config.switchProviderFirst')"
183
+ >
187
184
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
188
185
  <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
186
  <path d="M8 9h8"/>
@@ -193,10 +190,10 @@
193
190
  <button
194
191
  v-if="!provider.readOnly"
195
192
  class="card-action-btn"
196
- :class="{ loading: providerShareLoading[provider.name] }"
197
- disabled
193
+ :class="{ loading: providerShareLoading[provider.name], disabled: !shouldAllowProviderShare(provider) }"
194
+ :disabled="providerShareLoading[provider.name] || !shouldAllowProviderShare(provider)"
198
195
  @click="copyProviderShareCommand(provider)"
199
- title="分享命令(暂不可用)"
196
+ :title="shouldAllowProviderShare(provider) ? t('config.shareCommand') : t('config.shareDisabled')"
200
197
  aria-label="Share import command">
201
198
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
202
199
  <path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
@@ -5,14 +5,8 @@
5
5
  id="panel-config-openclaw"
6
6
  role="tabpanel"
7
7
  :aria-labelledby="'tab-config-openclaw'">
8
- <button class="btn-add" @click="openOpenclawAddModal" v-if="!loading && !initError">
9
- <svg class="icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="2">
10
- <path d="M10 4v12M4 10h12"/>
11
- </svg>
12
- 新增 OpenClaw 配置
13
- </button>
14
8
  <div class="config-template-hint">
15
- 写入 <code>~/.openclaw/openclaw.json</code>,支持 JSON5。
9
+ {{ t('openclaw.applyHint') }}
16
10
  </div>
17
11
 
18
12
  <div class="selector-section">
@@ -20,27 +14,27 @@
20
14
  <span class="selector-title">AGENTS.md</span>
21
15
  </div>
22
16
  <div class="config-template-hint">
23
- 读写 Workspace 的 <code>AGENTS.md</code>,默认路径 <code>~/.openclaw/workspace/AGENTS.md</code>。
17
+ {{ t('openclaw.agents.hint') }}
24
18
  </div>
25
19
  <button class="btn-tool" @click="openOpenclawAgentsEditor" :disabled="loading || !!initError || agentsLoading">
26
- {{ agentsLoading ? '加载中...' : '打开 AGENTS.md' }}
20
+ {{ agentsLoading ? t('config.modelLoading') : t('openclaw.agents.open') }}
27
21
  </button>
28
22
  </div>
29
23
 
30
24
  <div class="selector-section">
31
25
  <div class="selector-header">
32
- <label class="selector-title" for="openclaw-workspace-file">工作区文件</label>
26
+ <label class="selector-title" for="openclaw-workspace-file">{{ t('openclaw.workspaceFile') }}</label>
33
27
  </div>
34
28
  <input
35
29
  id="openclaw-workspace-file"
36
30
  class="form-input"
37
31
  v-model="openclawWorkspaceFileName"
38
- placeholder="例如: SOUL.md">
32
+ :placeholder="t('openclaw.workspace.placeholder')">
39
33
  <div class="config-template-hint">
40
- 仅限 Workspace 内的 <code>.md</code> 文件。
34
+ {{ t('openclaw.workspace.hint') }}
41
35
  </div>
42
36
  <button class="btn-tool" @click="openOpenclawWorkspaceEditor" :disabled="loading || !!initError || agentsLoading">
43
- {{ agentsLoading ? '加载中...' : '打开工作区文件' }}
37
+ {{ agentsLoading ? t('config.modelLoading') : t('openclaw.workspace.open') }}
44
38
  </button>
45
39
  </div>
46
40
 
@@ -62,16 +56,16 @@
62
56
  </div>
63
57
  <div class="card-trailing">
64
58
  <span :class="['pill', openclawHasContent(config) ? 'configured' : 'empty']">
65
- {{ openclawHasContent(config) ? '已配置' : '未配置' }}
59
+ {{ openclawHasContent(config) ? t('openclaw.configured') : t('openclaw.notConfigured') }}
66
60
  </span>
67
61
  <div class="card-actions" @click.stop>
68
- <button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="`Edit OpenClaw config ${name}`" title="编辑">
62
+ <button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="`Edit OpenClaw config ${name}`" :title="t('openclaw.action.edit')">
69
63
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
70
64
  <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
71
65
  <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
72
66
  </svg>
73
67
  </button>
74
- <button class="card-action-btn delete" @click="deleteOpenclawConfig(name)" :aria-label="`Delete OpenClaw config ${name}`" title="删除">
68
+ <button v-if="name !== '默认配置'" class="card-action-btn delete" @click="deleteOpenclawConfig(name)" :aria-label="`Delete OpenClaw config ${name}`" :title="t('openclaw.action.delete')">
75
69
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
76
70
  <path d="M3 6h18"/>
77
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"/>
@@ -0,0 +1,147 @@
1
+ <div
2
+ v-show="mainTab === 'docs'"
3
+ class="mode-content docs-mode-content"
4
+ id="panel-docs"
5
+ role="tabpanel"
6
+ aria-labelledby="tab-docs">
7
+ <div class="selector-section docs-overview-section">
8
+ <div class="selector-header docs-overview-header">
9
+ <div>
10
+ <span class="selector-title">{{ t('docs.title') }}</span>
11
+ <div class="skills-panel-note docs-section-note">{{ t('docs.subtitle') }}</div>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="docs-toolbar-grid">
16
+ <div class="docs-toolbar-card">
17
+ <label class="form-label" for="docs-install-package-manager">{{ t('common.packageManager') }}</label>
18
+ <select id="docs-install-package-manager" class="form-input" v-model="installPackageManager">
19
+ <option value="npm">npm</option>
20
+ <option value="pnpm">pnpm</option>
21
+ <option value="bun">bun</option>
22
+ </select>
23
+ </div>
24
+
25
+ <div class="docs-toolbar-card docs-toolbar-card-wide">
26
+ <label class="form-label">{{ t('common.mirror') }}</label>
27
+ <div class="install-action-tabs">
28
+ <button type="button" class="btn-mini" :class="{ active: installRegistryPreset === 'default' }" @click="setInstallRegistryPreset('default')">{{ t('common.official') }}</button>
29
+ <button type="button" class="btn-mini" :class="{ active: installRegistryPreset === 'npmmirror' }" @click="setInstallRegistryPreset('npmmirror')">npmmirror</button>
30
+ <button type="button" class="btn-mini" :class="{ active: installRegistryPreset === 'tencent' }" @click="setInstallRegistryPreset('tencent')">{{ t('docs.registry.tencent') }}</button>
31
+ <button type="button" class="btn-mini" :class="{ active: installRegistryPreset === 'custom' }" @click="setInstallRegistryPreset('custom')">{{ t('common.custom') }}</button>
32
+ </div>
33
+ <input
34
+ v-if="installRegistryPreset === 'custom'"
35
+ v-model="installRegistryCustom"
36
+ class="form-input install-registry-input"
37
+ placeholder="https://registry.example.com">
38
+ <div class="form-hint install-registry-hint" v-if="installRegistryPreview">
39
+ {{ t('docs.registryHintPrefix') }} --registry={{ installRegistryPreview }}
40
+ </div>
41
+ <div class="form-hint install-registry-hint" v-else-if="installRegistryPreset === 'custom'">
42
+ {{ t('docs.registryHintCustom') }}
43
+ </div>
44
+ </div>
45
+
46
+ <div class="docs-toolbar-card docs-toolbar-card-wide">
47
+ <label class="form-label">{{ t('common.action') }}</label>
48
+ <div class="install-action-tabs">
49
+ <button type="button" class="btn-mini" :class="{ active: installCommandAction === 'install' }" @click="setInstallCommandAction('install')">{{ t('common.install') }}</button>
50
+ <button type="button" class="btn-mini" :class="{ active: installCommandAction === 'update' }" @click="setInstallCommandAction('update')">{{ t('common.update') }}</button>
51
+ <button type="button" class="btn-mini" :class="{ active: installCommandAction === 'uninstall' }" @click="setInstallCommandAction('uninstall')">{{ t('common.uninstall') }}</button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+
56
+ <div class="docs-summary-strip">
57
+ <div class="docs-summary-item">
58
+ <span class="docs-summary-label">{{ t('common.targets') }}</span>
59
+ <strong class="docs-summary-value">{{ installTargetCards.length }}</strong>
60
+ </div>
61
+ <div class="docs-summary-item">
62
+ <span class="docs-summary-label">{{ t('common.currentPm') }}</span>
63
+ <strong class="docs-summary-value">{{ String(installPackageManager || 'npm').toUpperCase() }}</strong>
64
+ </div>
65
+ <div class="docs-summary-item">
66
+ <span class="docs-summary-label">{{ t('common.currentAction') }}</span>
67
+ <strong class="docs-summary-value">{{ installCommandAction === 'update' ? t('common.update') : (installCommandAction === 'uninstall' ? t('common.uninstall') : t('common.install')) }}</strong>
68
+ </div>
69
+ <div class="docs-summary-item docs-summary-item-wide">
70
+ <span class="docs-summary-label">{{ t('common.mirrorActive') }}</span>
71
+ <strong class="docs-summary-value">{{ installRegistryPreview || t('common.defaultOfficial') }}</strong>
72
+ </div>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="selector-section docs-command-section">
77
+ <div class="selector-header docs-section-header">
78
+ <div>
79
+ <span class="selector-title">{{ t('docs.section.commands') }}</span>
80
+ <div class="skills-panel-note docs-section-note">{{ t('docs.section.commandsNote') }}</div>
81
+ </div>
82
+ </div>
83
+
84
+ <div class="install-list docs-install-list">
85
+ <div
86
+ class="install-row docs-install-row"
87
+ v-for="target in installTargetCards"
88
+ :key="'docs-install-command-' + target.id + '-' + installCommandAction">
89
+ <div class="install-row-main">
90
+ <div class="docs-command-head">
91
+ <div class="install-row-title">{{ target.name }}</div>
92
+ <div class="docs-command-meta">
93
+ <span class="docs-meta-pill">{{ target.packageName }}</span>
94
+ <span class="docs-meta-pill">bin: {{ target.bin }}</span>
95
+ </div>
96
+ </div>
97
+ <div class="docs-command-row">
98
+ <div class="docs-command-box" role="group" :aria-label="`${target.name} command`">
99
+ <code class="install-command">{{ target.command }}</code>
100
+ <button
101
+ type="button"
102
+ class="btn-mini docs-copy-btn"
103
+ :disabled="!target.command"
104
+ @click="copyInstallCommand(target.command)">{{ t('common.copy') }}</button>
105
+ </div>
106
+ </div>
107
+ <div
108
+ v-if="target.id === 'codex' && target.termuxCommand && target.termuxCommand !== target.command"
109
+ class="docs-command-row docs-command-row-secondary">
110
+ <div class="docs-command-box" role="group" :aria-label="t('docs.termuxAria')">
111
+ <code class="install-command"><span class="docs-command-prefix">{{ t('docs.termuxLabel') }}</span>{{ target.termuxCommand }}</code>
112
+ <button
113
+ type="button"
114
+ class="btn-mini docs-copy-btn"
115
+ @click="copyInstallCommand(target.termuxCommand)">{{ t('common.copy') }}</button>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+
123
+ <div class="selector-section docs-help-section">
124
+ <div class="selector-header docs-section-header">
125
+ <div>
126
+ <span class="selector-title">{{ t('docs.section.faq') }}</span>
127
+ <div class="skills-panel-note docs-section-note">{{ t('docs.section.faqNote') }}</div>
128
+ </div>
129
+ </div>
130
+
131
+ <div class="docs-help-grid">
132
+ <div class="docs-note-card">
133
+ <div class="docs-note-title">{{ t('common.troubleshooting') }}</div>
134
+ <ul class="install-help-list docs-help-list">
135
+ <li v-for="tip in installTroubleshootingTips" :key="tip">{{ tip }}</li>
136
+ </ul>
137
+ </div>
138
+ <div class="docs-note-card">
139
+ <div class="docs-note-title">{{ t('common.rules') }}</div>
140
+ <ul class="docs-static-list">
141
+ <li>{{ t('docs.rule.1') }}</li>
142
+ <li>{{ t('docs.rule.2') }}</li>
143
+ </ul>
144
+ </div>
145
+ </div>
146
+ </div>
147
+ </div>