codexmate 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/README.zh.md +4 -2
- package/cli/auth-profiles.js +23 -7
- package/cli/doctor-core.js +903 -0
- package/cli/import-skills-url.js +334 -0
- package/cli.js +304 -208
- package/lib/cli-models-utils.js +0 -40
- package/lib/cli-network-utils.js +28 -2
- package/package.json +5 -2
- package/plugins/README.md +20 -0
- package/plugins/README.zh-CN.md +20 -0
- package/plugins/prompt-templates/comment-polish/index.mjs +25 -0
- package/plugins/prompt-templates/computed.mjs +253 -0
- package/plugins/prompt-templates/index.mjs +8 -0
- package/plugins/prompt-templates/manifest.mjs +15 -0
- package/plugins/prompt-templates/methods.mjs +619 -0
- package/plugins/prompt-templates/overview.mjs +90 -0
- package/plugins/prompt-templates/ownership.mjs +19 -0
- package/plugins/prompt-templates/rule-ack/index.mjs +21 -0
- package/plugins/prompt-templates/storage.mjs +64 -0
- package/plugins/registry.mjs +16 -0
- package/res/logo-pack.webp +0 -0
- package/web-ui/app.js +15 -32
- package/web-ui/index.html +4 -3
- package/web-ui/modules/app.computed.dashboard.mjs +22 -22
- package/web-ui/modules/app.computed.main-tabs.mjs +3 -0
- package/web-ui/modules/app.methods.agents.mjs +91 -3
- package/web-ui/modules/app.methods.codex-config.mjs +153 -164
- package/web-ui/modules/app.methods.navigation.mjs +34 -1
- package/web-ui/modules/app.methods.runtime.mjs +24 -2
- package/web-ui/modules/app.methods.session-browser.mjs +9 -2
- package/web-ui/modules/config-mode.computed.mjs +1 -3
- package/web-ui/modules/i18n.dict.mjs +2039 -0
- package/web-ui/modules/i18n.mjs +2 -1769
- package/web-ui/partials/index/layout-header.html +36 -32
- package/web-ui/partials/index/modal-config-template-agents.html +3 -4
- package/web-ui/partials/index/modal-health-check.html +33 -60
- package/web-ui/partials/index/panel-config-claude.html +35 -15
- package/web-ui/partials/index/panel-config-codex.html +47 -19
- package/web-ui/partials/index/panel-config-openclaw.html +8 -3
- package/web-ui/partials/index/panel-dashboard.html +186 -0
- package/web-ui/partials/index/panel-docs.html +1 -1
- package/web-ui/partials/index/panel-market.html +3 -0
- package/web-ui/partials/index/panel-orchestration.html +3 -0
- package/web-ui/partials/index/panel-plugins.html +16 -10
- package/web-ui/partials/index/panel-sessions.html +4 -1
- package/web-ui/partials/index/panel-settings.html +1 -1
- package/web-ui/partials/index/panel-usage.html +2 -1
- package/web-ui/styles/controls-forms.css +9 -2
- package/web-ui/styles/dashboard.css +274 -0
- package/web-ui/styles/layout-shell.css +2 -2
- package/web-ui/styles/sessions-list.css +3 -3
- package/web-ui/styles/sessions-usage.css +9 -0
- package/web-ui/styles.css +1 -0
- package/res/logo.png +0 -0
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
<div id="app" class="container" v-cloak>
|
|
2
|
-
<div v-if="!sessionStandalone" class="top-tabs" role="tablist" aria-label="
|
|
2
|
+
<div v-if="!sessionStandalone" class="top-tabs" role="tablist" :aria-label="t('nav.topTabs.aria')">
|
|
3
|
+
<button class="top-tab"
|
|
4
|
+
id="tab-dashboard"
|
|
5
|
+
role="tab"
|
|
6
|
+
data-main-tab="dashboard"
|
|
7
|
+
:tabindex="mainTab === 'dashboard' ? 0 : -1"
|
|
8
|
+
:aria-selected="mainTab === 'dashboard'"
|
|
9
|
+
aria-controls="panel-dashboard"
|
|
10
|
+
:class="{ active: isMainTabNavActive('dashboard') }"
|
|
11
|
+
@pointerdown="onMainTabPointerDown('dashboard', $event)"
|
|
12
|
+
@click="onMainTabClick('dashboard', $event)">{{ t('tab.dashboard') }}</button>
|
|
3
13
|
<button class="top-tab"
|
|
4
14
|
id="tab-docs"
|
|
5
15
|
role="tab"
|
|
@@ -11,38 +21,16 @@
|
|
|
11
21
|
@pointerdown="onMainTabPointerDown('docs', $event)"
|
|
12
22
|
@click="onMainTabClick('docs', $event)">{{ t('tab.docs') }}</button>
|
|
13
23
|
<button class="top-tab"
|
|
14
|
-
id="tab-config
|
|
24
|
+
id="tab-config"
|
|
15
25
|
role="tab"
|
|
16
26
|
data-main-tab="config"
|
|
17
|
-
data-config-mode="
|
|
18
|
-
:tabindex="mainTab === 'config'
|
|
19
|
-
:aria-selected="mainTab === 'config'
|
|
20
|
-
aria-controls="panel-config-provider"
|
|
21
|
-
:class="{ active:
|
|
22
|
-
@pointerdown="
|
|
23
|
-
@click="
|
|
24
|
-
<button class="top-tab"
|
|
25
|
-
id="tab-config-claude"
|
|
26
|
-
role="tab"
|
|
27
|
-
data-main-tab="config"
|
|
28
|
-
data-config-mode="claude"
|
|
29
|
-
:tabindex="mainTab === 'config' && configMode === 'claude' ? 0 : -1"
|
|
30
|
-
:aria-selected="mainTab === 'config' && configMode === 'claude'"
|
|
31
|
-
aria-controls="panel-config-claude"
|
|
32
|
-
:class="{ active: isConfigModeNavActive('claude') }"
|
|
33
|
-
@pointerdown="onConfigTabPointerDown('claude', $event)"
|
|
34
|
-
@click="onConfigTabClick('claude', $event)">{{ t('tab.config.claude') }}</button>
|
|
35
|
-
<button class="top-tab"
|
|
36
|
-
id="tab-config-openclaw"
|
|
37
|
-
role="tab"
|
|
38
|
-
data-main-tab="config"
|
|
39
|
-
data-config-mode="openclaw"
|
|
40
|
-
:tabindex="mainTab === 'config' && configMode === 'openclaw' ? 0 : -1"
|
|
41
|
-
:aria-selected="mainTab === 'config' && configMode === 'openclaw'"
|
|
42
|
-
aria-controls="panel-config-openclaw"
|
|
43
|
-
:class="{ active: isConfigModeNavActive('openclaw') }"
|
|
44
|
-
@pointerdown="onConfigTabPointerDown('openclaw', $event)"
|
|
45
|
-
@click="onConfigTabClick('openclaw', $event)">{{ t('tab.config.openclaw') }}</button>
|
|
27
|
+
:data-config-mode="configMode"
|
|
28
|
+
:tabindex="mainTab === 'config' ? 0 : -1"
|
|
29
|
+
:aria-selected="mainTab === 'config'"
|
|
30
|
+
:aria-controls="configMode === 'claude' ? 'panel-config-claude' : (configMode === 'openclaw' ? 'panel-config-openclaw' : 'panel-config-provider')"
|
|
31
|
+
:class="{ active: isMainTabNavActive('config') }"
|
|
32
|
+
@pointerdown="onMainTabPointerDown('config', $event)"
|
|
33
|
+
@click="onMainTabClick('config', $event)">{{ t('tab.config') }}</button>
|
|
46
34
|
<button class="top-tab"
|
|
47
35
|
id="tab-sessions"
|
|
48
36
|
role="tab"
|
|
@@ -126,7 +114,7 @@
|
|
|
126
114
|
<aside class="side-rail" v-if="!sessionStandalone">
|
|
127
115
|
<div class="brand-block">
|
|
128
116
|
<div class="brand-head">
|
|
129
|
-
<img class="brand-logo" src="/res/logo.
|
|
117
|
+
<img class="brand-logo" src="/res/logo-pack.webp" alt="Codex Mate logo">
|
|
130
118
|
<div class="brand-copy">
|
|
131
119
|
<div class="brand-kicker">{{ t('brand.kicker.workspace') }}</div>
|
|
132
120
|
<div class="brand-title">Codex Mate</div>
|
|
@@ -136,6 +124,22 @@
|
|
|
136
124
|
</div>
|
|
137
125
|
|
|
138
126
|
<div class="side-rail-nav">
|
|
127
|
+
<div class="side-section" role="navigation" :aria-label="t('side.overview')">
|
|
128
|
+
<div class="side-section-title">{{ t('side.overview') }}</div>
|
|
129
|
+
<button
|
|
130
|
+
id="side-tab-dashboard"
|
|
131
|
+
data-main-tab="dashboard"
|
|
132
|
+
:aria-current="mainTab === 'dashboard' ? 'page' : null"
|
|
133
|
+
:class="['side-item', { active: isMainTabNavActive('dashboard') }]"
|
|
134
|
+
@pointerdown="onMainTabPointerDown('dashboard', $event)"
|
|
135
|
+
@click="onMainTabClick('dashboard', $event)">
|
|
136
|
+
<div class="side-item-title">{{ t('side.overview.doctor') }}</div>
|
|
137
|
+
<div class="side-item-meta">
|
|
138
|
+
<span>{{ t('side.overview.doctor.meta') }}</span>
|
|
139
|
+
<span>{{ inspectorHealthStatus }}</span>
|
|
140
|
+
</div>
|
|
141
|
+
</button>
|
|
142
|
+
</div>
|
|
139
143
|
<div class="side-section" role="navigation" :aria-label="t('side.docs')">
|
|
140
144
|
<div class="side-section-title">{{ t('side.docs') }}</div>
|
|
141
145
|
<button
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
|
|
108
108
|
|
|
109
109
|
<div class="form-group">
|
|
110
|
-
<label class="form-label">{{ t('modal.agents.contentLabel') }}</label>
|
|
110
|
+
<label class="form-label">{{ t(agentsContext === 'claude-md' ? 'modal.agents.contentLabel.claudeMd' : 'modal.agents.contentLabel') }}</label>
|
|
111
111
|
<div
|
|
112
112
|
v-if="!agentsLoading && (hasAgentsContentChanged() || agentsDiffVisible)"
|
|
113
113
|
class="agents-diff-save-alert">
|
|
@@ -137,13 +137,12 @@
|
|
|
137
137
|
</div>
|
|
138
138
|
</div>
|
|
139
139
|
<textarea
|
|
140
|
-
v-else
|
|
141
140
|
v-model="agentsContent"
|
|
142
141
|
class="form-input template-editor"
|
|
143
142
|
spellcheck="false"
|
|
144
|
-
:readonly="agentsLoading || agentsSaving"
|
|
143
|
+
:readonly="agentsLoading || agentsSaving || agentsDiffVisible"
|
|
145
144
|
@input="onAgentsContentInput"
|
|
146
|
-
:placeholder="t('modal.agents.placeholder')"></textarea>
|
|
145
|
+
:placeholder="t(agentsContext === 'claude-md' ? 'modal.agents.placeholder.claudeMd' : 'modal.agents.placeholder')"></textarea>
|
|
147
146
|
<div class="template-editor-warning">
|
|
148
147
|
{{ agentsModalHint }}
|
|
149
148
|
<div class="agents-diff-hint">{{ t('modal.agents.hint.shortcuts') }}</div>
|
|
@@ -1,72 +1,45 @@
|
|
|
1
|
-
<div v-if="
|
|
2
|
-
<div class="modal
|
|
3
|
-
<div class="modal-
|
|
4
|
-
<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
|
-
</div>
|
|
8
|
-
<div v-if="healthCheckDialogLockedProvider" class="health-check-dialog-lock">
|
|
9
|
-
{{ t('modal.healthCheck.lockedPrefix', { value: healthCheckDialogLockedProvider }) }}
|
|
10
|
-
</div>
|
|
11
|
-
</div>
|
|
1
|
+
<div v-if="showHealthCheckModal" class="modal-overlay" @click.self="showHealthCheckModal = false">
|
|
2
|
+
<div class="modal" role="dialog" aria-modal="true" aria-labelledby="health-check-modal-title">
|
|
3
|
+
<div class="modal-title" id="health-check-modal-title">{{ t('config.health.title') }}</div>
|
|
12
4
|
|
|
13
|
-
<div class="
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class="form-select"
|
|
19
|
-
:disabled="!!healthCheckDialogLockedProvider || healthCheckDialogSending">
|
|
20
|
-
<option value="" disabled>{{ t('placeholder.selectProvider') }}</option>
|
|
21
|
-
<option v-for="provider in displayProvidersList" :key="'health-check-provider-' + provider.name" :value="provider.name">
|
|
22
|
-
{{ provider.name }}
|
|
23
|
-
</option>
|
|
24
|
-
</select>
|
|
5
|
+
<div v-if="!healthCheckResult" class="state-message">{{ t('common.notLoaded') }}</div>
|
|
6
|
+
<template v-else>
|
|
7
|
+
<div class="form-hint">
|
|
8
|
+
{{ healthCheckResult.ok ? t('config.health.ok') : t('config.health.fail') }}
|
|
9
|
+
<span v-if="healthCheckResult.issues">({{ t('config.health.issues', { count: healthCheckResult.issues.length }) }})</span>
|
|
25
10
|
</div>
|
|
26
|
-
<div v-if="healthCheckDialogLastResult" class="health-check-dialog-result" :class="healthCheckDialogLastResult.ok ? 'ok' : 'error'">
|
|
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
|
-
<span v-if="healthCheckDialogLastResult.status">HTTP {{ healthCheckDialogLastResult.status }}</span>
|
|
30
|
-
<span v-if="healthCheckDialogLastResult.durationMs">{{ healthCheckDialogLastResult.durationMs }} ms</span>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
11
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{{
|
|
12
|
+
<div v-if="healthCheckResult.remote && healthCheckResult.remote.type === 'remote-health-check'" class="form-hint">
|
|
13
|
+
{{ healthCheckResult.remote.endpoint || '' }}
|
|
14
|
+
<span v-if="healthCheckResult.remote.statusCode"> · {{ healthCheckResult.remote.statusCode }}</span>
|
|
15
|
+
<span v-if="healthCheckResult.remote.message"> · {{ healthCheckResult.remote.message }}</span>
|
|
37
16
|
</div>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
<span
|
|
46
|
-
<span v-if="
|
|
17
|
+
|
|
18
|
+
<div v-if="healthCheckResult.remote && healthCheckResult.remote.speedTests" class="model-list">
|
|
19
|
+
<div
|
|
20
|
+
v-for="(result, name) in healthCheckResult.remote.speedTests"
|
|
21
|
+
:key="'health-speed-' + name"
|
|
22
|
+
class="model-item"
|
|
23
|
+
>
|
|
24
|
+
<span>{{ name }}</span>
|
|
25
|
+
<span v-if="result && result.ok" class="latency ok">{{ formatLatency(result) }}</span>
|
|
26
|
+
<span v-else class="latency error">{{ (result && result.error) ? result.error : t('config.health.fail') }}</span>
|
|
47
27
|
</div>
|
|
48
|
-
<div class="health-check-message-text">{{ item.text }}</div>
|
|
49
|
-
<pre v-if="item.rawPreview" class="health-check-message-raw">{{ item.rawPreview }}</pre>
|
|
50
28
|
</div>
|
|
51
|
-
</div>
|
|
52
29
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
</div>
|
|
30
|
+
<div v-if="healthCheckResult.issues && healthCheckResult.issues.length" class="model-list">
|
|
31
|
+
<div
|
|
32
|
+
v-for="(issue, index) in healthCheckResult.issues"
|
|
33
|
+
:key="issue.code || ('health-issue-' + index)"
|
|
34
|
+
class="model-item"
|
|
35
|
+
>
|
|
36
|
+
<span>{{ issue.message || issue.code || '' }}</span>
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</template>
|
|
64
40
|
|
|
65
41
|
<div class="btn-group">
|
|
66
|
-
<button class="btn btn-
|
|
67
|
-
<button class="btn btn-confirm" @click="sendHealthCheckDialogMessage" :disabled="healthCheckDialogSending">
|
|
68
|
-
{{ healthCheckDialogSending ? t('common.sending') : t('modal.healthCheck.send') }}
|
|
69
|
-
</button>
|
|
42
|
+
<button class="btn btn-confirm" @click="showHealthCheckModal = false">{{ t('common.close') }}</button>
|
|
70
43
|
</div>
|
|
71
44
|
</div>
|
|
72
45
|
</div>
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
class="mode-content mode-cards"
|
|
5
5
|
id="panel-config-claude"
|
|
6
6
|
role="tabpanel"
|
|
7
|
-
:aria-labelledby="'tab-config-claude'">
|
|
7
|
+
:aria-labelledby="forceCompactLayout ? 'tab-config' : 'side-tab-config-claude'">
|
|
8
|
+
<div v-if="forceCompactLayout && !sessionStandalone" class="segmented-control">
|
|
9
|
+
<button type="button" :class="['segment', { active: configMode === 'codex' }]" @click="switchConfigMode('codex')">{{ t('tab.config.codex') }}</button>
|
|
10
|
+
<button type="button" :class="['segment', { active: configMode === 'claude' }]" @click="switchConfigMode('claude')">{{ t('tab.config.claude') }}</button>
|
|
11
|
+
<button type="button" :class="['segment', { active: configMode === 'openclaw' }]" @click="switchConfigMode('openclaw')">{{ t('tab.config.openclaw') }}</button>
|
|
12
|
+
</div>
|
|
8
13
|
<template v-if="shouldShowCliInstallPlaceholder('claude')">
|
|
9
14
|
<div class="selector-section">
|
|
10
15
|
<div class="empty-state">
|
|
@@ -89,22 +94,37 @@
|
|
|
89
94
|
|
|
90
95
|
<div class="selector-section">
|
|
91
96
|
<div class="selector-header">
|
|
92
|
-
<span class="selector-title">
|
|
97
|
+
<span class="selector-title">CLAUDE.md</span>
|
|
93
98
|
</div>
|
|
94
|
-
<button class="btn-tool" @click="
|
|
95
|
-
{{
|
|
99
|
+
<button class="btn-tool" @click="openClaudeMdEditor" :disabled="loading || !!initError || agentsLoading">
|
|
100
|
+
{{ agentsLoading ? t('config.modelLoading') : t('claude.md.open') }}
|
|
96
101
|
</button>
|
|
102
|
+
<div class="config-template-hint">
|
|
103
|
+
{{ t('claude.md.hint') }}
|
|
104
|
+
</div>
|
|
97
105
|
</div>
|
|
98
106
|
|
|
99
107
|
<div class="selector-section">
|
|
100
108
|
<div class="selector-header">
|
|
101
|
-
<span class="selector-title">
|
|
109
|
+
<span class="selector-title">{{ t('claude.health.title') }}</span>
|
|
102
110
|
</div>
|
|
103
|
-
<button class="btn-tool" @click="
|
|
104
|
-
{{
|
|
111
|
+
<button class="btn-tool" @click="runHealthCheck" :disabled="healthCheckLoading || loading || !!initError">
|
|
112
|
+
{{ healthCheckLoading ? t('claude.health.running') : t('claude.health.run') }}
|
|
105
113
|
</button>
|
|
106
|
-
<div class="config-template-hint">
|
|
107
|
-
|
|
114
|
+
<div class="config-template-hint">{{ t('claude.health.hint') }}</div>
|
|
115
|
+
<div v-if="healthCheckLoading && healthCheckBatchTotal" class="config-template-hint">
|
|
116
|
+
{{ t('claude.health.progress', { done: healthCheckBatchDone, total: healthCheckBatchTotal, failed: healthCheckBatchFailed }) }}
|
|
117
|
+
</div>
|
|
118
|
+
<div v-if="healthCheckResult && !healthCheckLoading" class="config-template-hint">
|
|
119
|
+
{{ healthCheckResult.ok ? t('config.health.ok') : t('config.health.fail') }} · {{ t('config.health.issues', { count: (healthCheckResult.issues || []).length }) }}
|
|
120
|
+
</div>
|
|
121
|
+
<button v-if="healthCheckResult && !healthCheckLoading" type="button" class="btn-mini" @click="showHealthCheckModal = true">
|
|
122
|
+
{{ t('common.detail') }}
|
|
123
|
+
</button>
|
|
124
|
+
<div v-if="healthCheckResult && !healthCheckLoading && (healthCheckResult.issues || []).length">
|
|
125
|
+
<div v-for="(issue, index) in healthCheckResult.issues" :key="issue.code || ('issue-' + index)" class="config-template-hint">
|
|
126
|
+
{{ issue.message || issue.code || '' }}<span v-if="issue.suggestion"> · {{ issue.suggestion }}</span>
|
|
127
|
+
</div>
|
|
108
128
|
</div>
|
|
109
129
|
</div>
|
|
110
130
|
|
|
@@ -125,27 +145,27 @@
|
|
|
125
145
|
</div>
|
|
126
146
|
</div>
|
|
127
147
|
<div class="card-trailing">
|
|
128
|
-
<span :class="['pill', config.hasKey ? 'configured' : 'empty']">
|
|
129
|
-
{{ config.hasKey ? t('claude.configured') : t('claude.notConfigured') }}
|
|
130
|
-
</span>
|
|
131
148
|
<span v-if="claudeSpeedResults[name]" :class="['latency', claudeSpeedResults[name].ok ? 'ok' : 'error']">
|
|
132
149
|
{{ formatLatency(claudeSpeedResults[name]) }}
|
|
133
150
|
</span>
|
|
151
|
+
<span :class="['pill', config.hasKey ? 'configured' : 'empty']">
|
|
152
|
+
{{ config.hasKey ? t('claude.configured') : t('claude.notConfigured') }}
|
|
153
|
+
</span>
|
|
134
154
|
<div class="card-actions" @click.stop>
|
|
135
|
-
<button class="card-action-btn" @click="openEditConfigModal(name)" :aria-label="
|
|
155
|
+
<button class="card-action-btn" @click="openEditConfigModal(name)" :aria-label="t('claude.action.editAria', { name })" :title="t('claude.action.edit')">
|
|
136
156
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
137
157
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
138
158
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
139
159
|
</svg>
|
|
140
160
|
</button>
|
|
141
|
-
<button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled :title="t('claude.action.shareDisabled')" aria-label="
|
|
161
|
+
<button class="card-action-btn" :class="{ loading: claudeShareLoading[name] }" @click="copyClaudeShareCommand(name)" disabled :title="t('claude.action.shareDisabled')" :aria-label="t('config.shareCommand.aria')">
|
|
142
162
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
143
163
|
<path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
|
|
144
164
|
<path d="M16 6l-4-4-4 4"/>
|
|
145
165
|
<path d="M12 2v14"/>
|
|
146
166
|
</svg>
|
|
147
167
|
</button>
|
|
148
|
-
<button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="
|
|
168
|
+
<button class="card-action-btn delete" @click="deleteClaudeConfig(name)" :aria-label="t('claude.action.deleteAria', { name })" :title="t('claude.action.delete')">
|
|
149
169
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
150
170
|
<path d="M3 6h18"/>
|
|
151
171
|
<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"/>
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
class="mode-content mode-cards"
|
|
5
5
|
id="panel-config-provider"
|
|
6
6
|
role="tabpanel"
|
|
7
|
-
:aria-labelledby="'tab-config-' + configMode">
|
|
7
|
+
:aria-labelledby="forceCompactLayout ? 'tab-config' : ('side-tab-config-' + configMode)">
|
|
8
|
+
<div v-if="forceCompactLayout && !sessionStandalone" class="segmented-control">
|
|
9
|
+
<button type="button" :class="['segment', { active: configMode === 'codex' }]" @click="switchConfigMode('codex')">{{ t('tab.config.codex') }}</button>
|
|
10
|
+
<button type="button" :class="['segment', { active: configMode === 'claude' }]" @click="switchConfigMode('claude')">{{ t('tab.config.claude') }}</button>
|
|
11
|
+
<button type="button" :class="['segment', { active: configMode === 'openclaw' }]" @click="switchConfigMode('openclaw')">{{ t('tab.config.openclaw') }}</button>
|
|
12
|
+
</div>
|
|
8
13
|
<template v-if="isCodexConfigMode && shouldShowCliInstallPlaceholder('codex')">
|
|
9
14
|
<div class="selector-section">
|
|
10
15
|
<div class="empty-state">
|
|
@@ -38,8 +43,8 @@
|
|
|
38
43
|
<div class="selector-header">
|
|
39
44
|
<span class="selector-title">{{ t('config.models') }}</span>
|
|
40
45
|
<div class="selector-actions">
|
|
41
|
-
<button class="btn-icon" @click="showModelModal = true" aria-label="
|
|
42
|
-
<button class="btn-icon" @click="showModelListModal = true" aria-label="
|
|
46
|
+
<button class="btn-icon" @click="showModelModal = true" :aria-label="t('modal.modelAdd.title')" :title="t('modal.modelAdd.title')" v-if="modelsSource === 'legacy'">+</button>
|
|
47
|
+
<button class="btn-icon" @click="showModelListModal = true" :aria-label="t('modal.modelManage.title')" :title="t('modal.modelManage.title')" v-if="modelsSource === 'legacy'">≡</button>
|
|
43
48
|
</div>
|
|
44
49
|
</div>
|
|
45
50
|
<select
|
|
@@ -86,7 +91,7 @@
|
|
|
86
91
|
</div>
|
|
87
92
|
<select class="model-select" v-model="serviceTier" @change="onServiceTierChange">
|
|
88
93
|
<option value="fast">{{ t('config.serviceTier.fast') }}</option>
|
|
89
|
-
<option value="standard">standard</option>
|
|
94
|
+
<option value="standard">{{ t('config.serviceTier.standard') }}</option>
|
|
90
95
|
</select>
|
|
91
96
|
<div class="config-template-hint">
|
|
92
97
|
{{ t('config.serviceTier.hint', { field: 'service_tier' }) }}
|
|
@@ -163,6 +168,30 @@
|
|
|
163
168
|
</button>
|
|
164
169
|
</div>
|
|
165
170
|
|
|
171
|
+
<div class="selector-section">
|
|
172
|
+
<div class="selector-header">
|
|
173
|
+
<span class="selector-title">{{ t('config.health.title') }}</span>
|
|
174
|
+
</div>
|
|
175
|
+
<button class="btn-tool" @click="runHealthCheck" :disabled="healthCheckLoading || loading || !!initError">
|
|
176
|
+
{{ healthCheckLoading ? t('config.health.running') : t('config.health.run') }}
|
|
177
|
+
</button>
|
|
178
|
+
<div class="config-template-hint">{{ t('config.health.hint') }}</div>
|
|
179
|
+
<div v-if="healthCheckLoading && healthCheckBatchTotal" class="config-template-hint">
|
|
180
|
+
{{ t('config.health.progress', { done: healthCheckBatchDone, total: healthCheckBatchTotal, failed: healthCheckBatchFailed }) }}
|
|
181
|
+
</div>
|
|
182
|
+
<div v-if="healthCheckResult && !healthCheckLoading" class="config-template-hint">
|
|
183
|
+
{{ healthCheckResult.ok ? t('config.health.ok') : t('config.health.fail') }} · {{ t('config.health.issues', { count: (healthCheckResult.issues || []).length }) }}
|
|
184
|
+
</div>
|
|
185
|
+
<button v-if="healthCheckResult && !healthCheckLoading" type="button" class="btn-mini" @click="showHealthCheckModal = true">
|
|
186
|
+
{{ t('common.detail') }}
|
|
187
|
+
</button>
|
|
188
|
+
<div v-if="healthCheckResult && !healthCheckLoading && (healthCheckResult.issues || []).length">
|
|
189
|
+
<div v-for="(issue, index) in healthCheckResult.issues" :key="issue.code || ('issue-' + index)" class="config-template-hint">
|
|
190
|
+
{{ issue.message || issue.code || '' }}<span v-if="issue.suggestion"> · {{ issue.suggestion }}</span>
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</div>
|
|
194
|
+
|
|
166
195
|
</template>
|
|
167
196
|
|
|
168
197
|
<div v-if="!loading && !initError" class="card-list">
|
|
@@ -187,24 +216,23 @@
|
|
|
187
216
|
</div>
|
|
188
217
|
</div>
|
|
189
218
|
<div class="card-trailing">
|
|
190
|
-
<span :class="['pill', providerPillConfigured(provider) ? 'configured' : 'empty']">
|
|
191
|
-
{{ providerPillText(provider) }}
|
|
192
|
-
</span>
|
|
193
219
|
<span v-if="speedResults[provider.name]" :class="['latency', speedResults[provider.name].ok ? 'ok' : 'error']">
|
|
194
220
|
{{ formatLatency(speedResults[provider.name]) }}
|
|
195
221
|
</span>
|
|
222
|
+
<span :class="['pill', providerPillConfigured(provider) ? 'configured' : 'empty']">
|
|
223
|
+
{{ providerPillText(provider) }}
|
|
224
|
+
</span>
|
|
196
225
|
<div class="card-actions" @click.stop>
|
|
197
226
|
<button
|
|
198
227
|
class="card-action-btn"
|
|
199
|
-
|
|
200
|
-
:disabled="
|
|
201
|
-
|
|
202
|
-
:
|
|
228
|
+
:class="{ loading: speedLoading[provider.name] }"
|
|
229
|
+
:disabled="!!speedLoading[provider.name]"
|
|
230
|
+
@click="runSpeedTest(provider.name, { silent: true })"
|
|
231
|
+
:aria-label="t('config.availabilityTestAria', { name: provider.name })"
|
|
232
|
+
:title="t('config.availabilityTest')"
|
|
203
233
|
>
|
|
204
234
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
205
|
-
<path d="
|
|
206
|
-
<path d="M8 9h8"/>
|
|
207
|
-
<path d="M8 13h5"/>
|
|
235
|
+
<path d="M13 2L3 14h7l-1 8 12-14h-7l1-6z"/>
|
|
208
236
|
</svg>
|
|
209
237
|
</button>
|
|
210
238
|
<button
|
|
@@ -214,7 +242,7 @@
|
|
|
214
242
|
:disabled="providerShareLoading[provider.name] || !shouldAllowProviderShare(provider)"
|
|
215
243
|
@click="copyProviderShareCommand(provider)"
|
|
216
244
|
:title="shouldAllowProviderShare(provider) ? t('config.shareCommand') : t('config.shareDisabled')"
|
|
217
|
-
aria-label="
|
|
245
|
+
:aria-label="t('config.shareCommand.aria')">
|
|
218
246
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
219
247
|
<path d="M4 12v7a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-7"/>
|
|
220
248
|
<path d="M16 6l-4-4-4 4"/>
|
|
@@ -227,8 +255,8 @@
|
|
|
227
255
|
:class="{ disabled: !shouldShowProviderEdit(provider) }"
|
|
228
256
|
:disabled="!shouldShowProviderEdit(provider)"
|
|
229
257
|
@click="openEditModal(provider)"
|
|
230
|
-
:aria-label="
|
|
231
|
-
:title="shouldShowProviderEdit(provider) ? '
|
|
258
|
+
:aria-label="t('config.provider.edit.aria', { name: provider.name })"
|
|
259
|
+
:title="shouldShowProviderEdit(provider) ? t('common.edit') : t('common.notEditable')">
|
|
232
260
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
233
261
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
234
262
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
@@ -240,8 +268,8 @@
|
|
|
240
268
|
:class="{ disabled: !shouldShowProviderDelete(provider) }"
|
|
241
269
|
:disabled="!shouldShowProviderDelete(provider)"
|
|
242
270
|
@click="deleteProvider(provider.name)"
|
|
243
|
-
:aria-label="
|
|
244
|
-
:title="shouldShowProviderDelete(provider) ? '
|
|
271
|
+
:aria-label="t('config.provider.delete.aria', { name: provider.name })"
|
|
272
|
+
:title="shouldShowProviderDelete(provider) ? t('common.delete') : t('common.notDeletable')">
|
|
245
273
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
246
274
|
<path d="M3 6h18"/>
|
|
247
275
|
<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"/>
|
|
@@ -4,7 +4,12 @@
|
|
|
4
4
|
class="mode-content mode-cards"
|
|
5
5
|
id="panel-config-openclaw"
|
|
6
6
|
role="tabpanel"
|
|
7
|
-
:aria-labelledby="'tab-config-openclaw'">
|
|
7
|
+
:aria-labelledby="forceCompactLayout ? 'tab-config' : 'side-tab-config-openclaw'">
|
|
8
|
+
<div v-if="forceCompactLayout && !sessionStandalone" class="segmented-control">
|
|
9
|
+
<button type="button" :class="['segment', { active: configMode === 'codex' }]" @click="switchConfigMode('codex')">{{ t('tab.config.codex') }}</button>
|
|
10
|
+
<button type="button" :class="['segment', { active: configMode === 'claude' }]" @click="switchConfigMode('claude')">{{ t('tab.config.claude') }}</button>
|
|
11
|
+
<button type="button" :class="['segment', { active: configMode === 'openclaw' }]" @click="switchConfigMode('openclaw')">{{ t('tab.config.openclaw') }}</button>
|
|
12
|
+
</div>
|
|
8
13
|
<div class="config-template-hint">
|
|
9
14
|
{{ t('openclaw.applyHint') }}
|
|
10
15
|
</div>
|
|
@@ -59,13 +64,13 @@
|
|
|
59
64
|
{{ openclawHasContent(config) ? t('openclaw.configured') : t('openclaw.notConfigured') }}
|
|
60
65
|
</span>
|
|
61
66
|
<div class="card-actions" @click.stop>
|
|
62
|
-
<button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="
|
|
67
|
+
<button class="card-action-btn" @click="openOpenclawEditModal(name)" :aria-label="t('openclaw.action.editAria', { name })" :title="t('openclaw.action.edit')">
|
|
63
68
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
64
69
|
<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/>
|
|
65
70
|
<path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>
|
|
66
71
|
</svg>
|
|
67
72
|
</button>
|
|
68
|
-
<button v-if="name !== '默认配置'" class="card-action-btn delete" @click="deleteOpenclawConfig(name)" :aria-label="
|
|
73
|
+
<button v-if="name !== '默认配置'" class="card-action-btn delete" @click="deleteOpenclawConfig(name)" :aria-label="t('openclaw.action.deleteAria', { name })" :title="t('openclaw.action.delete')">
|
|
69
74
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
70
75
|
<path d="M3 6h18"/>
|
|
71
76
|
<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"/>
|