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
@@ -1,24 +1,74 @@
1
1
  <div v-if="showConfigTemplateModal" class="modal-overlay" @click.self="!configTemplateApplying && closeConfigTemplateModal()">
2
2
  <div class="modal modal-wide" role="dialog" aria-modal="true" aria-labelledby="config-template-modal-title">
3
- <div class="modal-title" id="config-template-modal-title">Config 模板编辑器(手动确认应用)</div>
3
+ <div class="modal-title" id="config-template-modal-title">{{ t('modal.configTemplate.title') }}</div>
4
4
 
5
5
  <div class="form-group">
6
- <label class="form-label">config.toml 模板</label>
6
+ <label class="form-label">{{ t('modal.configTemplate.label') }}</label>
7
+ <div v-if="configTemplateDiffVisible" class="agents-diff-container">
8
+ <div class="agents-diff-header">
9
+ <div class="agents-diff-title">
10
+ {{ t('diff.title.configTemplate') }}
11
+ <span v-if="configTemplateDiffLoading" class="agents-diff-subtitle">{{ t('diff.generating') }}</span>
12
+ <span v-else-if="configTemplateDiffError" class="agents-diff-subtitle">{{ t('diff.failed') }}</span>
13
+ <span v-else-if="!configTemplateDiffHasChanges" class="agents-diff-subtitle">{{ t('diff.noChanges') }}</span>
14
+ </div>
15
+ <div class="agents-diff-stats">
16
+ <span class="agents-diff-stat add">+{{ configTemplateDiffStats.added || 0 }}</span>
17
+ <span class="agents-diff-stat del">-{{ configTemplateDiffStats.removed || 0 }}</span>
18
+ <span class="agents-diff-stat">={{ configTemplateDiffStats.unchanged || 0 }}</span>
19
+ </div>
20
+ </div>
21
+ <div v-if="configTemplateDiffError" class="agents-diff-error">
22
+ {{ configTemplateDiffError }}
23
+ </div>
24
+ <div v-else class="agents-diff-lines">
25
+ <div
26
+ v-for="(line, index) in configTemplateDiffLines"
27
+ :key="line.key || (line.type + '-' + index)"
28
+ :class="['agents-diff-line', line.type]">
29
+ <span class="agents-diff-line-sign">
30
+ {{ line.type === 'add' ? '+' : (line.type === 'del' ? '-' : ' ') }}
31
+ </span>
32
+ <span class="agents-diff-line-text">{{ line.value }}</span>
33
+ </div>
34
+ </div>
35
+ </div>
7
36
  <textarea
37
+ v-else
8
38
  v-model="configTemplateContent"
9
39
  class="form-input template-editor"
10
40
  spellcheck="false"
11
- :readonly="configTemplateApplying"
12
- placeholder="在这里编辑 config.toml 模板内容"></textarea>
41
+ :readonly="configTemplateApplying || configTemplateDiffLoading"
42
+ @input="onConfigTemplateContentInput"
43
+ :placeholder="t('modal.configTemplate.placeholder')"></textarea>
13
44
  <div class="template-editor-warning">
14
- 工具不会自动改动 `config.toml`。只有点击“确认应用模板”后才写入。
45
+ <template v-if="configTemplateDiffConfirmEnabled">
46
+ {{ t('modal.configTemplate.mode.twoStep') }}
47
+ </template>
48
+ <template v-else>
49
+ {{ t('modal.configTemplate.mode.oneStep') }}
50
+ </template>
51
+ <div v-if="configTemplateDiffVisible && (configTemplateDiffLoading || configTemplateApplying)" class="agents-diff-hint">{{ t('diff.hint.busy') }}</div>
52
+ <div v-else-if="configTemplateDiffVisible && configTemplateDiffError" class="agents-diff-hint">{{ t('diff.hint.failedBack') }}</div>
53
+ <div v-else-if="configTemplateDiffVisible && !configTemplateDiffHasChanges" class="agents-diff-hint">{{ t('diff.hint.noChangesBack') }}</div>
54
+ <div v-else-if="configTemplateDiffVisible" class="agents-diff-hint">{{ t('diff.hint.previewMode') }}</div>
15
55
  </div>
16
56
  </div>
17
57
 
18
58
  <div class="btn-group">
19
- <button class="btn btn-cancel" @click="closeConfigTemplateModal" :disabled="configTemplateApplying">取消</button>
20
- <button class="btn btn-confirm" @click="applyConfigTemplate" :disabled="configTemplateApplying">
21
- {{ configTemplateApplying ? '应用中...' : '确认应用模板' }}
59
+ <button class="btn btn-cancel" @click="closeConfigTemplateModal" :disabled="configTemplateApplying || configTemplateDiffLoading">{{ t('common.cancel') }}</button>
60
+ <button
61
+ v-if="configTemplateDiffVisible"
62
+ class="btn"
63
+ @click="resetConfigTemplateDiffState"
64
+ :disabled="configTemplateApplying || configTemplateDiffLoading">
65
+ {{ t('common.backToEdit') }}
66
+ </button>
67
+ <button class="btn btn-confirm" @click="applyConfigTemplate" :disabled="configTemplateApplying || configTemplateDiffLoading || (configTemplateDiffVisible && !configTemplateDiffHasChanges)">
68
+ {{ configTemplateApplying
69
+ ? (configTemplateDiffVisible || !configTemplateDiffConfirmEnabled ? t('common.applying') : t('common.confirming'))
70
+ : (configTemplateDiffVisible || !configTemplateDiffConfirmEnabled ? t('common.apply') : t('common.confirm'))
71
+ }}
22
72
  </button>
23
73
  </div>
24
74
  </div>
@@ -33,35 +83,35 @@
33
83
  class="btn-mini btn-modal-copy"
34
84
  @click="exportAgentsContent"
35
85
  :disabled="agentsLoading">
36
- 导出
86
+ {{ t('modal.agents.export') }}
37
87
  </button>
38
88
  <button
39
89
  class="btn-mini btn-modal-copy"
40
90
  @click="copyAgentsContent"
41
91
  :disabled="agentsLoading">
42
- 复制
92
+ {{ t('modal.agents.copy') }}
43
93
  </button>
44
94
  </div>
45
95
  </div>
46
96
 
47
97
  <div class="modal-editor-body">
48
98
  <div class="form-group">
49
- <label class="form-label">目标文件</label>
99
+ <label class="form-label">{{ t('modal.agents.targetFile') }}</label>
50
100
  <div class="form-hint">
51
- {{ agentsPath || '未加载' }}
101
+ {{ agentsPath || t('common.notLoaded') }}
52
102
  <span v-if="agentsPath">
53
- ({{ agentsExists ? '已存在' : '不存在,将在保存时创建' }})
103
+ ({{ agentsExists ? t('common.exists') : t('common.notExistsWillCreateOnSave') }})
54
104
  </span>
55
105
  </div>
56
106
  </div>
57
107
 
58
108
 
59
109
  <div class="form-group">
60
- <label class="form-label">AGENTS.md 内容</label>
110
+ <label class="form-label">{{ t('modal.agents.contentLabel') }}</label>
61
111
  <div
62
112
  v-if="!agentsLoading && (hasAgentsContentChanged() || agentsDiffVisible)"
63
113
  class="agents-diff-save-alert">
64
- {{ agentsDiffVisible ? '预览模式:当前改动尚未保存,只有点击“应用”后才会写入文件。' : '检测到未保存改动:关闭页面或应用前请先保存。' }}
114
+ {{ agentsDiffVisible ? t('modal.agents.unsaved.previewModeHint') : t('modal.agents.unsaved.detectedHint') }}
65
115
  </div>
66
116
  <div v-if="agentsDiffVisible">
67
117
  <div
@@ -70,10 +120,10 @@
70
120
  <span class="agents-diff-stat add">+{{ agentsDiffStats.added }}</span>
71
121
  <span class="agents-diff-stat del">-{{ agentsDiffStats.removed }}</span>
72
122
  </div>
73
- <div v-if="agentsDiffLoading" class="state-message">生成差异中...</div>
123
+ <div v-if="agentsDiffLoading" class="state-message">{{ t('diff.generating') }}</div>
74
124
  <div v-else-if="agentsDiffError" class="state-message error">{{ agentsDiffError }}</div>
75
- <div v-else-if="agentsDiffTruncated" class="agents-diff-empty">内容过大,已跳过逐行差异预览</div>
76
- <div v-else-if="!agentsDiffHasChanges" class="agents-diff-empty">未检测到改动</div>
125
+ <div v-else-if="agentsDiffTruncated" class="agents-diff-empty">{{ t('diff.tooLargeSkip') }}</div>
126
+ <div v-else-if="!agentsDiffHasChanges" class="agents-diff-empty">{{ t('diff.noChanges') }}</div>
77
127
  <div v-else class="agents-diff-view agents-diff-editor">
78
128
  <div
79
129
  v-for="(line, index) in agentsDiffLines"
@@ -93,32 +143,32 @@
93
143
  spellcheck="false"
94
144
  :readonly="agentsLoading || agentsSaving"
95
145
  @input="onAgentsContentInput"
96
- placeholder="在这里编辑 AGENTS.md 内容"></textarea>
146
+ :placeholder="t('modal.agents.placeholder')"></textarea>
97
147
  <div class="template-editor-warning">
98
148
  {{ agentsModalHint }}
99
- <div class="agents-diff-hint">快捷键:Esc(差异预览时返回编辑,编辑时关闭窗口)。</div>
100
- <div v-if="!agentsDiffVisible" class="agents-diff-hint">保存需两步:先点击“确认”预览差异,再点击“应用”保存。</div>
101
- <div v-else-if="agentsDiffLoading || agentsSaving" class="agents-diff-hint">正在生成差异或应用中,操作暂不可用。</div>
102
- <div v-else-if="agentsDiffError" class="agents-diff-hint">差异预览失败,请返回编辑后重试。</div>
103
- <div v-else-if="!agentsDiffHasChanges" class="agents-diff-hint">未检测到改动,可返回编辑继续修改或取消退出。</div>
104
- <div v-else-if="agentsDiffTruncated" class="agents-diff-hint">内容过大,已跳过预览,可点击“应用”保存或“返回编辑”继续修改。</div>
105
- <div v-else class="agents-diff-hint">当前为预览模式,可点击“应用”保存或“返回编辑”继续修改。</div>
149
+ <div class="agents-diff-hint">{{ t('modal.agents.hint.shortcuts') }}</div>
150
+ <div v-if="!agentsDiffVisible" class="agents-diff-hint">{{ t('modal.agents.hint.twoStepSave') }}</div>
151
+ <div v-else-if="agentsDiffLoading || agentsSaving" class="agents-diff-hint">{{ t('diff.hint.busy') }}</div>
152
+ <div v-else-if="agentsDiffError" class="agents-diff-hint">{{ t('diff.hint.failedBack') }}</div>
153
+ <div v-else-if="!agentsDiffHasChanges" class="agents-diff-hint">{{ t('diff.hint.noChangesBack') }}</div>
154
+ <div v-else-if="agentsDiffTruncated" class="agents-diff-hint">{{ t('diff.viewHint.truncated') }}</div>
155
+ <div v-else class="agents-diff-hint">{{ t('diff.viewHint.preview') }}</div>
106
156
  </div>
107
157
  </div>
108
158
 
109
159
  </div>
110
160
 
111
161
  <div class="btn-group modal-editor-footer">
112
- <button class="btn btn-cancel" @click="closeAgentsModal" :disabled="agentsSaving || agentsDiffLoading">取消</button>
162
+ <button class="btn btn-cancel" @click="closeAgentsModal" :disabled="agentsSaving || agentsDiffLoading">{{ t('common.cancel') }}</button>
113
163
  <button
114
164
  v-if="agentsDiffVisible"
115
165
  class="btn"
116
166
  @click="resetAgentsDiffState"
117
167
  :disabled="agentsSaving || agentsDiffLoading">
118
- 返回编辑
168
+ {{ t('common.backToEdit') }}
119
169
  </button>
120
170
  <button class="btn btn-confirm" @click="applyAgentsContent" :disabled="agentsSaving || agentsLoading || agentsDiffLoading || (agentsDiffVisible && !agentsDiffHasChanges)">
121
- {{ agentsSaving ? (agentsDiffVisible ? '应用中...' : '确认中...') : (agentsDiffVisible ? '应用' : '确认') }}
171
+ {{ agentsSaving ? (agentsDiffVisible ? t('common.applying') : t('common.confirming')) : (agentsDiffVisible ? t('common.apply') : t('common.confirm')) }}
122
172
  </button>
123
173
  </div>
124
174
  </div>
@@ -5,7 +5,7 @@
5
5
  aria-modal="true"
6
6
  aria-describedby="confirm-dialog-message"
7
7
  :aria-labelledby="confirmDialogTitle ? 'confirm-dialog-title' : null"
8
- :aria-label="confirmDialogTitle ? null : '确认操作'">
8
+ :aria-label="confirmDialogTitle ? null : t('confirm.aria')">
9
9
  <div id="confirm-dialog-title" class="modal-title">{{ confirmDialogTitle }}</div>
10
10
  <div id="confirm-dialog-message" class="confirm-dialog-message">{{ confirmDialogMessage }}</div>
11
11
  <div class="btn-group confirm-dialog-actions">
@@ -2,30 +2,30 @@
2
2
  <div class="modal modal-wide health-check-dialog" role="dialog" aria-modal="true" aria-labelledby="health-check-dialog-title">
3
3
  <div class="modal-header">
4
4
  <div>
5
- <div class="modal-title" id="health-check-dialog-title">健康检测对话</div>
6
- <div class="health-check-dialog-subtitle">发一轮真实对话,直看可用性。</div>
5
+ <div class="modal-title" id="health-check-dialog-title">{{ t('modal.healthCheck.title') }}</div>
6
+ <div class="health-check-dialog-subtitle">{{ t('modal.healthCheck.subtitle') }}</div>
7
7
  </div>
8
8
  <div v-if="healthCheckDialogLockedProvider" class="health-check-dialog-lock">
9
- 已锁定:{{ healthCheckDialogLockedProvider }}
9
+ {{ t('modal.healthCheck.lockedPrefix', { value: healthCheckDialogLockedProvider }) }}
10
10
  </div>
11
11
  </div>
12
12
 
13
13
  <div class="health-check-dialog-controls">
14
14
  <div class="form-group health-check-dialog-provider">
15
- <label class="form-label">提供商</label>
15
+ <label class="form-label">{{ t('field.provider') }}</label>
16
16
  <select
17
17
  v-model="healthCheckDialogSelectedProvider"
18
18
  class="form-select"
19
19
  :disabled="!!healthCheckDialogLockedProvider || healthCheckDialogSending">
20
- <option value="" disabled>请选择提供商</option>
20
+ <option value="" disabled>{{ t('placeholder.selectProvider') }}</option>
21
21
  <option v-for="provider in displayProvidersList" :key="'health-check-provider-' + provider.name" :value="provider.name">
22
22
  {{ provider.name }}
23
23
  </option>
24
24
  </select>
25
25
  </div>
26
26
  <div v-if="healthCheckDialogLastResult" class="health-check-dialog-result" :class="healthCheckDialogLastResult.ok ? 'ok' : 'error'">
27
- <span>{{ healthCheckDialogLastResult.ok ? '已收到回复' : '本轮失败' }}</span>
28
- <span v-if="healthCheckDialogLastResult.model">模型:{{ healthCheckDialogLastResult.model }}</span>
27
+ <span>{{ healthCheckDialogLastResult.ok ? t('modal.healthCheck.result.ok') : t('modal.healthCheck.result.fail') }}</span>
28
+ <span v-if="healthCheckDialogLastResult.model">{{ t('label.model') }}{{ healthCheckDialogLastResult.model }}</span>
29
29
  <span v-if="healthCheckDialogLastResult.status">HTTP {{ healthCheckDialogLastResult.status }}</span>
30
30
  <span v-if="healthCheckDialogLastResult.durationMs">{{ healthCheckDialogLastResult.durationMs }} ms</span>
31
31
  </div>
@@ -33,14 +33,14 @@
33
33
 
34
34
  <div class="health-check-dialog-thread">
35
35
  <div v-if="healthCheckDialogMessages.length === 0" class="health-check-dialog-empty">
36
- 发一句话,看是否正常回复。
36
+ {{ t('modal.healthCheck.emptyHint') }}
37
37
  </div>
38
38
  <div
39
39
  v-for="item in healthCheckDialogMessages"
40
40
  :key="item.id"
41
41
  :class="['health-check-message', item.role, item.ok === false ? 'error' : '']">
42
42
  <div class="health-check-message-meta">
43
- <span>{{ item.role === 'user' ? '' : '提供商' }}</span>
43
+ <span>{{ item.role === 'user' ? t('role.you') : t('role.provider') }}</span>
44
44
  <span v-if="item.model">{{ item.model }}</span>
45
45
  <span v-if="item.status">HTTP {{ item.status }}</span>
46
46
  <span v-if="item.durationMs">{{ item.durationMs }} ms</span>
@@ -51,21 +51,21 @@
51
51
  </div>
52
52
 
53
53
  <div class="form-group">
54
- <label class="form-label">消息</label>
54
+ <label class="form-label">{{ t('field.message') }}</label>
55
55
  <textarea
56
56
  v-model="healthCheckDialogPrompt"
57
57
  class="form-input health-check-dialog-textarea"
58
58
  rows="4"
59
59
  :disabled="healthCheckDialogSending"
60
- placeholder="例如:请回复“连接正常”。"
60
+ :placeholder="t('placeholder.healthCheckPromptExample')"
61
61
  @keydown.ctrl.enter.prevent="sendHealthCheckDialogMessage"></textarea>
62
- <div class="form-hint">真实接口,单轮发送,不带历史。</div>
62
+ <div class="form-hint">{{ t('modal.healthCheck.realApiHint') }}</div>
63
63
  </div>
64
64
 
65
65
  <div class="btn-group">
66
- <button class="btn btn-cancel" @click="closeHealthCheckDialog()" :disabled="healthCheckDialogSending">关闭</button>
66
+ <button class="btn btn-cancel" @click="closeHealthCheckDialog()" :disabled="healthCheckDialogSending">{{ t('common.close') }}</button>
67
67
  <button class="btn btn-confirm" @click="sendHealthCheckDialogMessage" :disabled="healthCheckDialogSending">
68
- {{ healthCheckDialogSending ? '发送中...' : '发送检测' }}
68
+ {{ healthCheckDialogSending ? t('common.sending') : t('modal.healthCheck.send') }}
69
69
  </button>
70
70
  </div>
71
71
  </div>
@@ -3,21 +3,21 @@
3
3
  <div class="modal-title" id="openclaw-config-modal-title">{{ openclawEditorTitle }}</div>
4
4
 
5
5
  <div class="form-group">
6
- <label class="form-label">配置名称</label>
7
- <input v-model="openclawEditing.name" class="form-input" :readonly="openclawEditing.lockName" placeholder="例如: 默认配置">
6
+ <label class="form-label">{{ t('field.configName') }}</label>
7
+ <input v-model="openclawEditing.name" class="form-input" :readonly="openclawEditing.lockName" :placeholder="t('placeholder.openclawConfigNameExample')">
8
8
  </div>
9
9
 
10
10
  <div class="form-group">
11
- <label class="form-label">目标文件</label>
11
+ <label class="form-label">{{ t('field.targetFile') }}</label>
12
12
  <div class="form-hint">
13
- {{ openclawConfigPath || '未加载' }}
13
+ {{ openclawConfigPath || t('common.notLoaded') }}
14
14
  <span v-if="openclawConfigPath">
15
- ({{ openclawConfigExists ? '已存在' : '不存在,将在应用时创建' }})
15
+ ({{ openclawConfigExists ? t('common.exists') : t('common.notExistsWillCreateOnApply') }})
16
16
  </span>
17
17
  </div>
18
18
  <div class="btn-group" style="justify-content:flex-start;">
19
19
  <button class="btn btn-confirm secondary" @click="loadOpenclawConfigFromFile" :disabled="openclawFileLoading">
20
- {{ openclawFileLoading ? '加载中...' : '加载当前配置' }}
20
+ {{ openclawFileLoading ? t('common.loading') : t('modal.openclaw.loadCurrent') }}
21
21
  </button>
22
22
  </div>
23
23
  </div>
@@ -25,44 +25,48 @@
25
25
  <div class="quick-section">
26
26
  <div class="quick-header">
27
27
  <div>
28
- <div class="quick-title">新手快速配置</div>
29
- <div class="form-hint">按 3 步完成:填 Provider 和模型,写入编辑器,保存并应用。</div>
28
+ <div class="quick-title">{{ t('modal.openclaw.quick.title') }}</div>
29
+ <div class="form-hint">{{ t('modal.openclaw.quick.subtitle') }}</div>
30
30
  </div>
31
31
  <div class="quick-actions">
32
- <button class="btn-mini" @click="syncOpenclawQuickFromText">从编辑器读取</button>
33
- <button class="btn-mini" @click="resetOpenclawQuick">清空</button>
32
+ <button class="btn-mini" @click="syncOpenclawQuickFromText">{{ t('modal.openclaw.quick.readFromEditor') }}</button>
33
+ <button class="btn-mini" @click="resetOpenclawQuick">{{ t('common.clear') }}</button>
34
34
  </div>
35
35
  </div>
36
36
  <div class="quick-steps">
37
- <div class="quick-step"><span class="step-badge">1</span><span>填写 Provider 与模型</span></div>
38
- <div class="quick-step"><span class="step-badge">2</span><span>点击写入编辑器</span></div>
39
- <div class="quick-step"><span class="step-badge">3</span><span>保存并应用</span></div>
37
+ <div class="quick-step"><span class="step-badge">1</span><span>{{ t('modal.openclaw.quick.step1') }}</span></div>
38
+ <div class="quick-step"><span class="step-badge">2</span><span>{{ t('modal.openclaw.quick.step2') }}</span></div>
39
+ <div class="quick-step"><span class="step-badge">3</span><span>{{ t('modal.openclaw.quick.step3') }}</span></div>
40
40
  </div>
41
41
  <div class="quick-grid">
42
42
  <div class="quick-card">
43
43
  <div class="structured-card-title">Provider</div>
44
44
  <div class="form-group">
45
- <label class="form-label">Provider 名称</label>
45
+ <label class="form-label">{{ t('field.providerName') }}</label>
46
46
  <input v-model="openclawQuick.providerName" class="form-input" placeholder="例如: custom-myapi">
47
- <div class="form-hint">会拼成 provider/model 作为主模型标识。</div>
47
+ <div class="form-hint">{{ t('modal.openclaw.quick.providerHint') }}</div>
48
48
  </div>
49
49
  <div class="form-group">
50
- <label class="form-label">Base URL</label>
51
- <input v-model="openclawQuick.baseUrl" class="form-input" placeholder="https://api.example.com/v1">
50
+ <label class="form-label">{{ t('field.baseUrl') }}</label>
51
+ <input v-model="openclawQuick.baseUrl" class="form-input" placeholder="https://api.example.com/v1" :readonly="openclawQuick.baseUrlReadOnly">
52
+ <div v-if="openclawQuick.baseUrlDisplayKind === 'builtin-default'" class="form-hint">{{ t('modal.openclaw.quick.baseUrlHintDefault') }}</div>
53
+ <div v-else-if="openclawQuick.baseUrlReadOnly" class="form-hint">{{ t('modal.openclaw.quick.baseUrlHintReadonly') }}</div>
52
54
  </div>
53
55
  <div class="form-group">
54
56
  <label class="form-label">API Key</label>
55
57
  <div class="list-row">
56
- <input v-model="openclawQuick.apiKey" class="form-input" :type="openclawQuick.showKey ? 'text' : 'password'" placeholder="sk-...">
57
- <button class="btn-mini" @click="toggleOpenclawQuickKey">
58
- {{ openclawQuick.showKey ? '隐藏' : '显示' }}
58
+ <input v-model="openclawQuick.apiKey" class="form-input" :readonly="openclawQuick.apiKeyReadOnly" :type="(openclawQuick.apiKeyReadOnly || openclawQuick.showKey) ? 'text' : 'password'" placeholder="sk-...">
59
+ <button v-if="!openclawQuick.apiKeyReadOnly" class="btn-mini" @click="toggleOpenclawQuickKey">
60
+ {{ openclawQuick.showKey ? t('common.hide') : t('common.show') }}
59
61
  </button>
60
62
  </div>
61
- <div class="form-hint">留空表示不覆盖现有 key。</div>
63
+ <div v-if="openclawQuick.apiKeyDisplayKind === 'auth-profile-value'" class="form-hint">{{ t('modal.openclaw.quick.apiKeyHintFromAuth') }}</div>
64
+ <div v-else-if="openclawQuick.apiKeyReadOnly" class="form-hint">{{ t('modal.openclaw.quick.apiKeyHintReadonly') }}</div>
65
+ <div v-else class="form-hint">{{ t('modal.openclaw.quick.apiKeyHintKeep') }}</div>
62
66
  </div>
63
67
  <div class="form-group">
64
- <label class="form-label">API 类型</label>
65
- <input v-model="openclawQuick.apiType" class="form-input" list="openclawApiTypeList" placeholder="例如: openai-responses">
68
+ <label class="form-label">{{ t('field.apiType') }}</label>
69
+ <input v-model="openclawQuick.apiType" class="form-input" list="openclawApiTypeList" :placeholder="t('placeholder.apiTypeExample')">
66
70
  <datalist id="openclawApiTypeList">
67
71
  <option value="openai-responses"></option>
68
72
  <option value="openai-chat"></option>
@@ -73,51 +77,51 @@
73
77
  </div>
74
78
 
75
79
  <div class="quick-card">
76
- <div class="structured-card-title">模型</div>
80
+ <div class="structured-card-title">{{ t('modal.openclaw.quick.modelTitle') }}</div>
77
81
  <div class="form-group">
78
- <label class="form-label">模型 ID</label>
79
- <input v-model="openclawQuick.modelId" class="form-input" placeholder="例如: gpt-4.1">
82
+ <label class="form-label">{{ t('field.modelId') }}</label>
83
+ <input v-model="openclawQuick.modelId" class="form-input" :placeholder="t('placeholder.modelIdExample')">
80
84
  </div>
81
85
  <div class="form-group">
82
- <label class="form-label">展示名称</label>
83
- <input v-model="openclawQuick.modelName" class="form-input" placeholder="留空则使用模型 ID">
86
+ <label class="form-label">{{ t('field.displayName') }}</label>
87
+ <input v-model="openclawQuick.modelName" class="form-input" :placeholder="t('placeholder.modelNameOptional')">
84
88
  </div>
85
89
  <div class="form-group">
86
- <label class="form-label">上下文与最大输出</label>
90
+ <label class="form-label">{{ t('field.contextAndMaxOutput') }}</label>
87
91
  <div class="list-row">
88
- <input v-model="openclawQuick.contextWindow" class="form-input" placeholder="上下文长度">
89
- <input v-model="openclawQuick.maxTokens" class="form-input" placeholder="最大输出">
92
+ <input v-model="openclawQuick.contextWindow" class="form-input" :placeholder="t('field.contextWindow')">
93
+ <input v-model="openclawQuick.maxTokens" class="form-input" :placeholder="t('field.maxOutput')">
90
94
  </div>
91
- <div class="form-hint">留空表示不改动已有配置。</div>
95
+ <div class="form-hint">{{ t('hint.emptyNoChange') }}</div>
92
96
  </div>
93
97
  </div>
94
98
 
95
99
  <div class="quick-card">
96
- <div class="structured-card-title">选项</div>
100
+ <div class="structured-card-title">{{ t('modal.openclaw.quick.optionsTitle') }}</div>
97
101
  <label class="quick-option">
98
102
  <input type="checkbox" v-model="openclawQuick.setPrimary">
99
- 设为主模型
103
+ {{ t('modal.openclaw.quick.setPrimary') }}
100
104
  </label>
101
105
  <label class="quick-option">
102
106
  <input type="checkbox" v-model="openclawQuick.overrideProvider">
103
- 覆盖同名 Provider 基础信息
107
+ {{ t('modal.openclaw.quick.overrideProvider') }}
104
108
  </label>
105
109
  <label class="quick-option">
106
110
  <input type="checkbox" v-model="openclawQuick.overrideModels">
107
- 覆盖同名模型列表
111
+ {{ t('modal.openclaw.quick.overrideModels') }}
108
112
  </label>
109
- <div class="form-hint">关闭覆盖会只补空缺字段。</div>
113
+ <div class="form-hint">{{ t('modal.openclaw.quick.optionsHint') }}</div>
110
114
  </div>
111
115
  </div>
112
116
  <div class="btn-group">
113
- <button class="btn btn-confirm" @click="applyOpenclawQuickToText">写入编辑器</button>
117
+ <button class="btn btn-confirm" @click="applyOpenclawQuickToText">{{ t('modal.openclaw.quick.writeToEditor') }}</button>
114
118
  </div>
115
119
  </div>
116
120
 
117
121
  <div class="structured-section">
118
122
  <div class="structured-header">
119
123
  <span class="structured-title">结构化配置(高级)</span>
120
- <span class="form-hint">写入编辑器会重排 JSON,注释可能丢失。</span>
124
+ <span class="form-hint">{{ t('modal.openclaw.structured.writeHint') }}</span>
121
125
  </div>
122
126
  <div class="structured-grid">
123
127
  <div class="structured-card">
@@ -245,7 +249,7 @@
245
249
  </div>
246
250
  <div class="btn-group">
247
251
  <button class="btn btn-confirm secondary" @click="syncOpenclawStructuredFromText">从文本刷新</button>
248
- <button class="btn btn-confirm" @click="applyOpenclawStructuredToText">写入编辑器</button>
252
+ <button class="btn btn-confirm" @click="applyOpenclawStructuredToText">{{ t('common.writeToEditor') }}</button>
249
253
  </div>
250
254
  </div>
251
255
 
@@ -258,13 +262,14 @@
258
262
  :readonly="openclawSaving || openclawApplying"
259
263
  placeholder="在这里编辑 OpenClaw 配置(JSON5)"></textarea>
260
264
  <div class="template-editor-warning">
261
- 保存仅写入本地配置库。点击“保存并应用”后会写入 openclaw.json
265
+ <span v-if="openclawEditing.lockName && openclawEditing.name === '默认配置'">默认配置始终映射当前 openclaw.json,请直接使用“保存并应用”。</span>
266
+ <span v-else>保存仅写入本地配置库。点击“保存并应用”后会写入 openclaw.json。</span>
262
267
  </div>
263
268
  </div>
264
269
 
265
270
  <div class="btn-group">
266
271
  <button class="btn btn-cancel" @click="closeOpenclawConfigModal" :disabled="openclawSaving || openclawApplying">取消</button>
267
- <button class="btn btn-confirm" @click="saveOpenclawConfig" :disabled="openclawSaving || openclawApplying">
272
+ <button class="btn btn-confirm" @click="saveOpenclawConfig" :disabled="openclawSaving || openclawApplying || (openclawEditing.lockName && openclawEditing.name === '默认配置')">
268
273
  {{ openclawSaving ? '保存中...' : '保存' }}
269
274
  </button>
270
275
  <button class="btn btn-confirm secondary" @click="saveAndApplyOpenclawConfig" :disabled="openclawSaving || openclawApplying">