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.
- package/README.md +289 -152
- package/README.zh.md +321 -0
- package/cli/agents-files.js +224 -0
- package/cli/archive-helpers.js +446 -0
- package/cli/auth-profiles.js +359 -0
- package/cli/builtin-proxy.js +1044 -0
- package/cli/claude-proxy.js +998 -0
- package/cli/config-bootstrap.js +384 -0
- package/cli/openai-bridge.js +950 -0
- package/cli/openclaw-config.js +629 -0
- package/cli/session-usage.concurrent.js +28 -0
- package/cli/session-usage.js +112 -0
- package/cli/session-usage.models.js +176 -0
- package/cli/skills.js +1141 -0
- package/cli/zip-commands.js +510 -0
- package/cli.js +9408 -9719
- package/lib/cli-models-utils.js +109 -1
- package/lib/cli-path-utils.js +69 -0
- package/lib/cli-sessions.js +386 -0
- package/lib/download-artifacts.js +77 -0
- package/lib/task-orchestrator.js +869 -0
- package/package.json +14 -10
- package/res/logo.png +0 -0
- package/res/vue.global.prod.js +13 -0
- package/web-ui/app.js +193 -15
- package/web-ui/index.html +5 -1
- package/web-ui/logic.agents-diff.mjs +1 -1
- package/web-ui/logic.claude.mjs +60 -0
- package/web-ui/logic.runtime.mjs +11 -7
- package/web-ui/logic.sessions.mjs +372 -21
- package/web-ui/modules/api.mjs +22 -1
- package/web-ui/modules/app.computed.dashboard.mjs +23 -10
- package/web-ui/modules/app.computed.index.mjs +4 -0
- package/web-ui/modules/app.computed.main-tabs.mjs +198 -0
- package/web-ui/modules/app.computed.session.mjs +521 -9
- package/web-ui/modules/app.methods.agents.mjs +62 -11
- package/web-ui/modules/app.methods.codex-config.mjs +189 -34
- package/web-ui/modules/app.methods.index.mjs +7 -1
- package/web-ui/modules/app.methods.install.mjs +24 -20
- package/web-ui/modules/app.methods.navigation.mjs +142 -1
- package/web-ui/modules/app.methods.openclaw-core.mjs +339 -39
- package/web-ui/modules/app.methods.openclaw-editing.mjs +39 -4
- package/web-ui/modules/app.methods.openclaw-persist.mjs +122 -4
- package/web-ui/modules/app.methods.providers.mjs +192 -53
- package/web-ui/modules/app.methods.session-actions.mjs +99 -19
- package/web-ui/modules/app.methods.session-browser.mjs +196 -5
- package/web-ui/modules/app.methods.session-timeline.mjs +22 -15
- package/web-ui/modules/app.methods.session-trash.mjs +3 -0
- package/web-ui/modules/app.methods.startup-claude.mjs +70 -71
- package/web-ui/modules/app.methods.task-orchestration.mjs +471 -0
- package/web-ui/modules/config-mode.computed.mjs +2 -0
- package/web-ui/modules/config-template-confirm-pref.mjs +33 -0
- package/web-ui/modules/i18n.mjs +1609 -0
- package/web-ui/modules/plugins.computed.mjs +220 -0
- package/web-ui/modules/plugins.methods.mjs +620 -0
- package/web-ui/modules/plugins.storage.mjs +37 -0
- package/web-ui/partials/index/layout-footer.html +1 -57
- package/web-ui/partials/index/layout-header.html +299 -175
- package/web-ui/partials/index/modal-config-template-agents.html +79 -29
- package/web-ui/partials/index/modal-confirm-toast.html +1 -1
- package/web-ui/partials/index/modal-health-check.html +14 -14
- package/web-ui/partials/index/modal-openclaw-config.html +47 -42
- package/web-ui/partials/index/modal-skills.html +130 -114
- package/web-ui/partials/index/modals-basic.html +71 -102
- package/web-ui/partials/index/panel-config-claude.html +50 -12
- package/web-ui/partials/index/panel-config-codex.html +34 -37
- package/web-ui/partials/index/panel-config-openclaw.html +10 -16
- package/web-ui/partials/index/panel-docs.html +147 -0
- package/web-ui/partials/index/panel-market.html +38 -38
- package/web-ui/partials/index/panel-orchestration.html +397 -0
- package/web-ui/partials/index/panel-plugins.html +243 -0
- package/web-ui/partials/index/panel-sessions.html +51 -146
- package/web-ui/partials/index/panel-settings.html +188 -96
- package/web-ui/partials/index/panel-usage.html +353 -0
- package/web-ui/session-helpers.mjs +221 -10
- package/web-ui/styles/base-theme.css +120 -229
- package/web-ui/styles/controls-forms.css +59 -51
- package/web-ui/styles/docs-panel.css +247 -0
- package/web-ui/styles/layout-shell.css +394 -128
- package/web-ui/styles/modals-core.css +18 -3
- package/web-ui/styles/navigation-panels.css +184 -183
- package/web-ui/styles/plugins-panel.css +518 -0
- package/web-ui/styles/responsive.css +102 -62
- package/web-ui/styles/sessions-list.css +13 -27
- package/web-ui/styles/sessions-preview.css +13 -7
- package/web-ui/styles/sessions-toolbar-trash.css +25 -0
- package/web-ui/styles/sessions-usage.css +581 -6
- package/web-ui/styles/settings-panel.css +166 -0
- package/web-ui/styles/skills-list.css +16 -11
- package/web-ui/styles/skills-market.css +63 -2
- package/web-ui/styles/task-orchestration.css +776 -0
- package/web-ui/styles/titles-cards.css +67 -66
- package/web-ui/styles.css +4 -0
- package/README.en.md +0 -259
- package/res/screenshot.png +0 -0
- package/res/vue.global.js +0 -18552
|
@@ -1,45 +1,15 @@
|
|
|
1
1
|
<div id="app" class="container" v-cloak>
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<div class="hero-title">
|
|
14
|
-
Codex <span class="accent">Mate.</span>
|
|
15
|
-
</div>
|
|
16
|
-
<div class="hero-subtitle">
|
|
17
|
-
配置中枢:管理 Codex / Claude / OpenClaw / 会话
|
|
18
|
-
<span class="sr-only">本地配置中枢,统一管理 Codex / Claude Code / OpenClaw / 会话。</span>
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
<div v-if="!sessionStandalone" class="hero-github">
|
|
22
|
-
<a
|
|
23
|
-
class="github-badge github-badge-mobile"
|
|
24
|
-
href="https://github.com/SakuraByteCore/codexmate"
|
|
25
|
-
target="_blank"
|
|
26
|
-
rel="noopener"
|
|
27
|
-
title="打开 GitHub 仓库">
|
|
28
|
-
<span class="github-badge-left">
|
|
29
|
-
<svg class="github-badge-icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
30
|
-
<path fill="currentColor" d="M12 2C6.48 2 2 6.58 2 12.26c0 4.5 2.87 8.32 6.84 9.67.5.1.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.38-3.37-1.38-.45-1.19-1.11-1.5-1.11-1.5-.91-.64.07-.63.07-.63 1 .07 1.53 1.06 1.53 1.06.9 1.57 2.36 1.12 2.94.86.09-.66.35-1.12.63-1.38-2.22-.26-4.56-1.14-4.56-5.09 0-1.13.39-2.06 1.03-2.79-.1-.26-.45-1.31.1-2.73 0 0 .84-.28 2.75 1.06A9.36 9.36 0 0 1 12 6.8c.85 0 1.7.12 2.5.34 1.9-1.34 2.74-1.06 2.74-1.06.55 1.42.2 2.47.1 2.73.64.73 1.03 1.66 1.03 2.79 0 3.96-2.35 4.83-4.58 5.08.36.32.68.95.68 1.92 0 1.38-.01 2.5-.01 2.84 0 .27.18.59.69.49A10.04 10.04 0 0 0 22 12.26C22 6.58 17.52 2 12 2z"/>
|
|
31
|
-
</svg>
|
|
32
|
-
<span class="github-badge-label">GitHub</span>
|
|
33
|
-
</span>
|
|
34
|
-
<span class="github-badge-text" title="SakuraByteCore/codexmate">
|
|
35
|
-
<span class="github-owner">SakuraByteCore</span>
|
|
36
|
-
<span class="github-sep">/</span>
|
|
37
|
-
<span class="github-repo">codexmate</span>
|
|
38
|
-
</span>
|
|
39
|
-
</a>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div v-if="!sessionStandalone" class="top-tabs" role="tablist" aria-label="主导航">
|
|
2
|
+
<div v-if="!sessionStandalone" class="top-tabs" role="tablist" aria-label="Navigation">
|
|
3
|
+
<button class="top-tab"
|
|
4
|
+
id="tab-docs"
|
|
5
|
+
role="tab"
|
|
6
|
+
data-main-tab="docs"
|
|
7
|
+
:tabindex="mainTab === 'docs' ? 0 : -1"
|
|
8
|
+
:aria-selected="mainTab === 'docs'"
|
|
9
|
+
aria-controls="panel-docs"
|
|
10
|
+
:class="{ active: isMainTabNavActive('docs') }"
|
|
11
|
+
@pointerdown="onMainTabPointerDown('docs', $event)"
|
|
12
|
+
@click="onMainTabClick('docs', $event)">{{ t('tab.docs') }}</button>
|
|
43
13
|
<button class="top-tab"
|
|
44
14
|
id="tab-config-codex"
|
|
45
15
|
role="tab"
|
|
@@ -50,7 +20,7 @@
|
|
|
50
20
|
aria-controls="panel-config-provider"
|
|
51
21
|
:class="{ active: isConfigModeNavActive('codex') }"
|
|
52
22
|
@pointerdown="onConfigTabPointerDown('codex', $event)"
|
|
53
|
-
@click="onConfigTabClick('codex', $event)">
|
|
23
|
+
@click="onConfigTabClick('codex', $event)">{{ t('tab.config.codex') }}</button>
|
|
54
24
|
<button class="top-tab"
|
|
55
25
|
id="tab-config-claude"
|
|
56
26
|
role="tab"
|
|
@@ -61,7 +31,7 @@
|
|
|
61
31
|
aria-controls="panel-config-claude"
|
|
62
32
|
:class="{ active: isConfigModeNavActive('claude') }"
|
|
63
33
|
@pointerdown="onConfigTabPointerDown('claude', $event)"
|
|
64
|
-
@click="onConfigTabClick('claude', $event)">
|
|
34
|
+
@click="onConfigTabClick('claude', $event)">{{ t('tab.config.claude') }}</button>
|
|
65
35
|
<button class="top-tab"
|
|
66
36
|
id="tab-config-openclaw"
|
|
67
37
|
role="tab"
|
|
@@ -72,7 +42,7 @@
|
|
|
72
42
|
aria-controls="panel-config-openclaw"
|
|
73
43
|
:class="{ active: isConfigModeNavActive('openclaw') }"
|
|
74
44
|
@pointerdown="onConfigTabPointerDown('openclaw', $event)"
|
|
75
|
-
@click="onConfigTabClick('openclaw', $event)">
|
|
45
|
+
@click="onConfigTabClick('openclaw', $event)">{{ t('tab.config.openclaw') }}</button>
|
|
76
46
|
<button class="top-tab"
|
|
77
47
|
id="tab-sessions"
|
|
78
48
|
role="tab"
|
|
@@ -82,7 +52,27 @@
|
|
|
82
52
|
aria-controls="panel-sessions"
|
|
83
53
|
:class="{ active: isMainTabNavActive('sessions') }"
|
|
84
54
|
@pointerdown="onMainTabPointerDown('sessions', $event)"
|
|
85
|
-
@click="onMainTabClick('sessions', $event)"
|
|
55
|
+
@click="onMainTabClick('sessions', $event)">{{ t('tab.sessions') }}</button>
|
|
56
|
+
<button class="top-tab"
|
|
57
|
+
id="tab-usage"
|
|
58
|
+
role="tab"
|
|
59
|
+
data-main-tab="usage"
|
|
60
|
+
:tabindex="mainTab === 'usage' ? 0 : -1"
|
|
61
|
+
:aria-selected="mainTab === 'usage'"
|
|
62
|
+
aria-controls="panel-usage"
|
|
63
|
+
:class="{ active: isMainTabNavActive('usage') }"
|
|
64
|
+
@pointerdown="onMainTabPointerDown('usage', $event)"
|
|
65
|
+
@click="onMainTabClick('usage', $event)">{{ t('tab.usage') }}</button>
|
|
66
|
+
<button v-if="taskOrchestrationTabEnabled" class="top-tab"
|
|
67
|
+
id="tab-orchestration"
|
|
68
|
+
role="tab"
|
|
69
|
+
data-main-tab="orchestration"
|
|
70
|
+
:tabindex="mainTab === 'orchestration' ? 0 : -1"
|
|
71
|
+
:aria-selected="mainTab === 'orchestration'"
|
|
72
|
+
aria-controls="panel-orchestration"
|
|
73
|
+
:class="{ active: isMainTabNavActive('orchestration') }"
|
|
74
|
+
@pointerdown="onMainTabPointerDown('orchestration', $event)"
|
|
75
|
+
@click="onMainTabClick('orchestration', $event)">{{ t('tab.orchestration') }}</button>
|
|
86
76
|
<button class="top-tab"
|
|
87
77
|
id="tab-market"
|
|
88
78
|
role="tab"
|
|
@@ -92,7 +82,17 @@
|
|
|
92
82
|
aria-controls="panel-market"
|
|
93
83
|
:class="{ active: isMainTabNavActive('market') }"
|
|
94
84
|
@pointerdown="onMainTabPointerDown('market', $event)"
|
|
95
|
-
@click="onMainTabClick('market', $event)"
|
|
85
|
+
@click="onMainTabClick('market', $event)">{{ t('tab.market') }}</button>
|
|
86
|
+
<button class="top-tab"
|
|
87
|
+
id="tab-plugins"
|
|
88
|
+
role="tab"
|
|
89
|
+
data-main-tab="plugins"
|
|
90
|
+
:tabindex="mainTab === 'plugins' ? 0 : -1"
|
|
91
|
+
:aria-selected="mainTab === 'plugins'"
|
|
92
|
+
aria-controls="panel-plugins"
|
|
93
|
+
:class="{ active: isMainTabNavActive('plugins') }"
|
|
94
|
+
@pointerdown="onMainTabPointerDown('plugins', $event)"
|
|
95
|
+
@click="onMainTabClick('plugins', $event)">{{ t('tab.plugins') }}</button>
|
|
96
96
|
<button class="top-tab"
|
|
97
97
|
id="tab-settings"
|
|
98
98
|
role="tab"
|
|
@@ -102,43 +102,58 @@
|
|
|
102
102
|
aria-controls="panel-settings"
|
|
103
103
|
:class="{ active: isMainTabNavActive('settings') }"
|
|
104
104
|
@pointerdown="onMainTabPointerDown('settings', $event)"
|
|
105
|
-
@click="onMainTabClick('settings', $event)"
|
|
105
|
+
@click="onMainTabClick('settings', $event)">{{ t('tab.settings') }}</button>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<div v-if="!sessionStandalone" class="lang-fab" role="group" :aria-label="t('lang.label')">
|
|
109
|
+
<div class="lang-choice" role="group" :aria-label="t('lang.label')">
|
|
110
|
+
<button
|
|
111
|
+
type="button"
|
|
112
|
+
class="lang-choice-btn"
|
|
113
|
+
:aria-pressed="(lang || 'zh') === 'zh'"
|
|
114
|
+
:class="{ active: (lang || 'zh') === 'zh' }"
|
|
115
|
+
@click="setLang('zh')">ZH</button>
|
|
116
|
+
<button
|
|
117
|
+
type="button"
|
|
118
|
+
class="lang-choice-btn"
|
|
119
|
+
:aria-pressed="(lang || 'zh') === 'en'"
|
|
120
|
+
:class="{ active: (lang || 'zh') === 'en' }"
|
|
121
|
+
@click="setLang('en')">EN</button>
|
|
122
|
+
</div>
|
|
106
123
|
</div>
|
|
107
124
|
|
|
108
125
|
<div :class="['app-shell', { standalone: sessionStandalone }]">
|
|
109
126
|
<aside class="side-rail" v-if="!sessionStandalone">
|
|
110
127
|
<div class="brand-block">
|
|
111
|
-
<div class="brand-
|
|
128
|
+
<div class="brand-head">
|
|
112
129
|
<img class="brand-logo" src="/res/logo.png" alt="Codex Mate logo">
|
|
130
|
+
<div class="brand-copy">
|
|
131
|
+
<div class="brand-kicker">Workspace</div>
|
|
132
|
+
<div class="brand-title">Codex Mate</div>
|
|
133
|
+
</div>
|
|
113
134
|
</div>
|
|
114
|
-
<div class="brand-
|
|
115
|
-
Codex <span class="accent">Mate</span>
|
|
116
|
-
</div>
|
|
117
|
-
<div class="brand-subtitle">
|
|
118
|
-
配置 / 会话切换器
|
|
119
|
-
</div>
|
|
120
|
-
<a
|
|
121
|
-
class="github-badge github-badge-rail"
|
|
122
|
-
href="https://github.com/SakuraByteCore/codexmate"
|
|
123
|
-
target="_blank"
|
|
124
|
-
rel="noopener"
|
|
125
|
-
title="打开 GitHub 仓库">
|
|
126
|
-
<span class="github-badge-left">
|
|
127
|
-
<svg class="github-badge-icon" viewBox="0 0 24 24" aria-hidden="true">
|
|
128
|
-
<path fill="currentColor" d="M12 2C6.48 2 2 6.58 2 12.26c0 4.5 2.87 8.32 6.84 9.67.5.1.68-.22.68-.49 0-.24-.01-.88-.01-1.73-2.78.62-3.37-1.38-3.37-1.38-.45-1.19-1.11-1.5-1.11-1.5-.91-.64.07-.63.07-.63 1 .07 1.53 1.06 1.53 1.06.9 1.57 2.36 1.12 2.94.86.09-.66.35-1.12.63-1.38-2.22-.26-4.56-1.14-4.56-5.09 0-1.13.39-2.06 1.03-2.79-.1-.26-.45-1.31.1-2.73 0 0 .84-.28 2.75 1.06A9.36 9.36 0 0 1 12 6.8c.85 0 1.7.12 2.5.34 1.9-1.34 2.74-1.06 2.74-1.06.55 1.42.2 2.47.1 2.73.64.73 1.03 1.66 1.03 2.79 0 3.96-2.35 4.83-4.58 5.08.36.32.68.95.68 1.92 0 1.38-.01 2.5-.01 2.84 0 .27.18.59.69.49A10.04 10.04 0 0 0 22 12.26C22 6.58 17.52 2 12 2z"/>
|
|
129
|
-
</svg>
|
|
130
|
-
<span class="github-badge-label">GitHub</span>
|
|
131
|
-
</span>
|
|
132
|
-
<span class="github-badge-text" title="SakuraByteCore/codexmate">
|
|
133
|
-
<span class="github-owner">SakuraByteCore</span>
|
|
134
|
-
<span class="github-sep">/</span>
|
|
135
|
-
<span class="github-repo">codexmate</span>
|
|
136
|
-
</span>
|
|
137
|
-
</a>
|
|
135
|
+
<div class="brand-subtitle">Local config & sessions workspace</div>
|
|
138
136
|
</div>
|
|
139
137
|
|
|
140
|
-
<div class="side-
|
|
141
|
-
|
|
138
|
+
<div class="side-rail-nav">
|
|
139
|
+
<div class="side-section" role="navigation" :aria-label="t('side.docs')">
|
|
140
|
+
<div class="side-section-title">{{ t('side.docs') }}</div>
|
|
141
|
+
<button
|
|
142
|
+
id="side-tab-docs"
|
|
143
|
+
data-main-tab="docs"
|
|
144
|
+
:aria-current="mainTab === 'docs' ? 'page' : null"
|
|
145
|
+
:class="['side-item', { active: isMainTabNavActive('docs') }]"
|
|
146
|
+
@pointerdown="onMainTabPointerDown('docs', $event)"
|
|
147
|
+
@click="onMainTabClick('docs', $event)">
|
|
148
|
+
<div class="side-item-title">{{ t('side.docs.cliInstall') }}</div>
|
|
149
|
+
<div class="side-item-meta">
|
|
150
|
+
<span>{{ t('side.docs.cliInstall.meta') }}</span>
|
|
151
|
+
<span>{{ String(installPackageManager || 'npm').toUpperCase() }} · {{ installCommandAction === 'update' ? t('common.update') : (installCommandAction === 'uninstall' ? t('common.uninstall') : t('common.install')) }}</span>
|
|
152
|
+
</div>
|
|
153
|
+
</button>
|
|
154
|
+
</div>
|
|
155
|
+
<div class="side-section" role="navigation" :aria-label="t('side.config')">
|
|
156
|
+
<div class="side-section-title">{{ t('side.config') }}</div>
|
|
142
157
|
<button
|
|
143
158
|
id="side-tab-config-codex"
|
|
144
159
|
data-main-tab="config"
|
|
@@ -147,10 +162,10 @@
|
|
|
147
162
|
:class="['side-item', { active: isConfigModeNavActive('codex') }]"
|
|
148
163
|
@pointerdown="onConfigTabPointerDown('codex', $event)"
|
|
149
164
|
@click="onConfigTabClick('codex', $event)">
|
|
150
|
-
<div class="side-item-title">
|
|
165
|
+
<div class="side-item-title">{{ t('side.config.codex') }}</div>
|
|
151
166
|
<div class="side-item-meta">
|
|
152
|
-
<span
|
|
153
|
-
<span v-if="currentProvider"
|
|
167
|
+
<span>{{ t('side.config.codex.meta') }}</span>
|
|
168
|
+
<span v-if="currentProvider">{{ t('common.current', { value: currentProvider }) }}</span>
|
|
154
169
|
</div>
|
|
155
170
|
</button>
|
|
156
171
|
<button
|
|
@@ -161,10 +176,10 @@
|
|
|
161
176
|
:class="['side-item', { active: isConfigModeNavActive('claude') }]"
|
|
162
177
|
@pointerdown="onConfigTabPointerDown('claude', $event)"
|
|
163
178
|
@click="onConfigTabClick('claude', $event)">
|
|
164
|
-
<div class="side-item-title">
|
|
179
|
+
<div class="side-item-title">{{ t('side.config.claude') }}</div>
|
|
165
180
|
<div class="side-item-meta">
|
|
166
|
-
<span>
|
|
167
|
-
<span v-if="currentClaudeConfig"
|
|
181
|
+
<span>{{ t('side.config.claude.meta') }}</span>
|
|
182
|
+
<span v-if="currentClaudeConfig">{{ t('common.current', { value: currentClaudeConfig }) }}</span>
|
|
168
183
|
</div>
|
|
169
184
|
</button>
|
|
170
185
|
<button
|
|
@@ -175,16 +190,16 @@
|
|
|
175
190
|
:class="['side-item', { active: isConfigModeNavActive('openclaw') }]"
|
|
176
191
|
@pointerdown="onConfigTabPointerDown('openclaw', $event)"
|
|
177
192
|
@click="onConfigTabClick('openclaw', $event)">
|
|
178
|
-
<div class="side-item-title">
|
|
193
|
+
<div class="side-item-title">{{ t('side.config.openclaw') }}</div>
|
|
179
194
|
<div class="side-item-meta">
|
|
180
|
-
<span>
|
|
181
|
-
<span v-if="currentOpenclawConfig"
|
|
195
|
+
<span>{{ t('side.config.openclaw.meta') }}</span>
|
|
196
|
+
<span v-if="currentOpenclawConfig">{{ t('common.current', { value: currentOpenclawConfig }) }}</span>
|
|
182
197
|
</div>
|
|
183
198
|
</button>
|
|
184
199
|
</div>
|
|
185
200
|
|
|
186
|
-
<div class="side-section" role="navigation" aria-label="
|
|
187
|
-
<div class="side-section-title"
|
|
201
|
+
<div class="side-section" role="navigation" :aria-label="t('side.sessions')">
|
|
202
|
+
<div class="side-section-title">{{ t('side.sessions') }}</div>
|
|
188
203
|
<button
|
|
189
204
|
id="side-tab-sessions"
|
|
190
205
|
data-main-tab="sessions"
|
|
@@ -192,16 +207,46 @@
|
|
|
192
207
|
:class="['side-item', { active: isMainTabNavActive('sessions') }]"
|
|
193
208
|
@pointerdown="onMainTabPointerDown('sessions', $event)"
|
|
194
209
|
@click="onMainTabClick('sessions', $event)">
|
|
195
|
-
<div class="side-item-title"
|
|
210
|
+
<div class="side-item-title">{{ t('side.sessions.browser') }}</div>
|
|
196
211
|
<div class="side-item-meta">
|
|
197
|
-
<span
|
|
198
|
-
<span
|
|
212
|
+
<span>{{ t('side.sessions.browser.meta') }}</span>
|
|
213
|
+
<span>{{ t('sessions.sourceLabel', { value: (sessionFilterSource === 'all' ? t('sessions.source.all') : (sessionFilterSource === 'codex' ? 'Codex' : 'Claude')) }) }}</span>
|
|
214
|
+
</div>
|
|
215
|
+
</button>
|
|
216
|
+
<button
|
|
217
|
+
id="side-tab-usage"
|
|
218
|
+
data-main-tab="usage"
|
|
219
|
+
:aria-current="mainTab === 'usage' ? 'page' : null"
|
|
220
|
+
:class="['side-item', { active: isMainTabNavActive('usage') }]"
|
|
221
|
+
@pointerdown="onMainTabPointerDown('usage', $event)"
|
|
222
|
+
@click="onMainTabClick('usage', $event)">
|
|
223
|
+
<div class="side-item-title">{{ t('tab.usage') }}</div>
|
|
224
|
+
<div class="side-item-meta">
|
|
225
|
+
<span>{{ t('side.usage.meta') }}</span>
|
|
226
|
+
<span>{{ t('usage.rangeLabel', { value: (sessionsUsageTimeRange === 'all' ? t('usage.range.all') : (sessionsUsageTimeRange === '30d' ? t('usage.range.30d.short') : t('usage.range.7d.short'))) }) }}</span>
|
|
199
227
|
</div>
|
|
200
228
|
</button>
|
|
201
229
|
</div>
|
|
202
230
|
|
|
203
|
-
<div class="side-section" role="navigation" aria-label="
|
|
204
|
-
<div class="side-section-title"
|
|
231
|
+
<div v-if="taskOrchestrationTabEnabled" class="side-section" role="navigation" :aria-label="t('side.orchestration')">
|
|
232
|
+
<div class="side-section-title">{{ t('side.orchestration') }}</div>
|
|
233
|
+
<button
|
|
234
|
+
id="side-tab-orchestration"
|
|
235
|
+
data-main-tab="orchestration"
|
|
236
|
+
:aria-current="mainTab === 'orchestration' ? 'page' : null"
|
|
237
|
+
:class="['side-item', { active: isMainTabNavActive('orchestration') }]"
|
|
238
|
+
@pointerdown="onMainTabPointerDown('orchestration', $event)"
|
|
239
|
+
@click="onMainTabClick('orchestration', $event)">
|
|
240
|
+
<div class="side-item-title">{{ t('tab.orchestration') }}</div>
|
|
241
|
+
<div class="side-item-meta">
|
|
242
|
+
<span>{{ t('side.orchestration.meta') }}</span>
|
|
243
|
+
<span>{{ t('orchestration.queueStats', { running: taskOrchestrationQueueStats.running, queued: taskOrchestrationQueueStats.queued }) }}</span>
|
|
244
|
+
</div>
|
|
245
|
+
</button>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
<div class="side-section" role="navigation" :aria-label="t('side.skills')">
|
|
249
|
+
<div class="side-section-title">{{ t('side.skills') }}</div>
|
|
205
250
|
<button
|
|
206
251
|
id="side-tab-market"
|
|
207
252
|
data-main-tab="market"
|
|
@@ -209,16 +254,33 @@
|
|
|
209
254
|
:class="['side-item', { active: isMainTabNavActive('market') }]"
|
|
210
255
|
@pointerdown="onMainTabPointerDown('market', $event)"
|
|
211
256
|
@click="onMainTabClick('market', $event)">
|
|
212
|
-
<div class="side-item-title"
|
|
257
|
+
<div class="side-item-title">{{ t('tab.market') }}</div>
|
|
213
258
|
<div class="side-item-meta">
|
|
214
|
-
<span>{{ skillsTargetLabel }}
|
|
215
|
-
<span
|
|
259
|
+
<span>{{ t('skills.localLabel', { target: skillsTargetLabel }) }}</span>
|
|
260
|
+
<span>{{ t('skills.counts', { installed: skillsList.length, importable: skillsImportList.length }) }}</span>
|
|
216
261
|
</div>
|
|
217
262
|
</button>
|
|
218
263
|
</div>
|
|
219
264
|
|
|
220
|
-
<div class="side-section" role="navigation" aria-label="
|
|
221
|
-
<div class="side-section-title"
|
|
265
|
+
<div class="side-section" role="navigation" :aria-label="t('side.plugins')">
|
|
266
|
+
<div class="side-section-title">{{ t('side.plugins') }}</div>
|
|
267
|
+
<button
|
|
268
|
+
id="side-tab-plugins"
|
|
269
|
+
data-main-tab="plugins"
|
|
270
|
+
:aria-current="mainTab === 'plugins' ? 'page' : null"
|
|
271
|
+
:class="['side-item', { active: isMainTabNavActive('plugins') }]"
|
|
272
|
+
@pointerdown="onMainTabPointerDown('plugins', $event)"
|
|
273
|
+
@click="onMainTabClick('plugins', $event)">
|
|
274
|
+
<div class="side-item-title">{{ t('side.plugins.tools') }}</div>
|
|
275
|
+
<div class="side-item-meta">
|
|
276
|
+
<span>{{ t('side.plugins.tools.meta') }}</span>
|
|
277
|
+
<span>{{ promptTemplatesList.length }} templates</span>
|
|
278
|
+
</div>
|
|
279
|
+
</button>
|
|
280
|
+
</div>
|
|
281
|
+
|
|
282
|
+
<div class="side-section" role="navigation" :aria-label="t('side.system')">
|
|
283
|
+
<div class="side-section-title">{{ t('side.system') }}</div>
|
|
222
284
|
<button
|
|
223
285
|
id="side-tab-settings"
|
|
224
286
|
data-main-tab="settings"
|
|
@@ -226,112 +288,174 @@
|
|
|
226
288
|
:class="['side-item', { active: isMainTabNavActive('settings') }]"
|
|
227
289
|
@pointerdown="onMainTabPointerDown('settings', $event)"
|
|
228
290
|
@click="onMainTabClick('settings', $event)">
|
|
229
|
-
<div class="side-item-title"
|
|
291
|
+
<div class="side-item-title">{{ t('side.system.settings') }}</div>
|
|
230
292
|
<div class="side-item-meta">
|
|
231
|
-
<span
|
|
293
|
+
<span>{{ t('side.system.settings.meta') }}</span>
|
|
232
294
|
</div>
|
|
233
295
|
</button>
|
|
234
296
|
</div>
|
|
297
|
+
</div>
|
|
298
|
+
|
|
299
|
+
<div class="side-rail-lang" role="group" :aria-label="t('lang.label')">
|
|
300
|
+
<div class="lang-choice" role="group" :aria-label="t('lang.label')">
|
|
301
|
+
<button
|
|
302
|
+
type="button"
|
|
303
|
+
class="lang-choice-btn"
|
|
304
|
+
:aria-pressed="(lang || 'zh') === 'zh'"
|
|
305
|
+
:class="{ active: (lang || 'zh') === 'zh' }"
|
|
306
|
+
@click="setLang('zh')">ZH</button>
|
|
307
|
+
<button
|
|
308
|
+
type="button"
|
|
309
|
+
class="lang-choice-btn"
|
|
310
|
+
:aria-pressed="(lang || 'zh') === 'en'"
|
|
311
|
+
:class="{ active: (lang || 'zh') === 'en' }"
|
|
312
|
+
@click="setLang('en')">EN</button>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
235
315
|
</aside>
|
|
236
316
|
<main class="main-panel">
|
|
237
|
-
<div class="panel-
|
|
238
|
-
<
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
</
|
|
245
|
-
<p class="subtitle" v-else-if="mainTab === 'sessions'">
|
|
246
|
-
统一查看与导出 Codex / Claude 会话。
|
|
247
|
-
</p>
|
|
248
|
-
<p class="subtitle" v-else-if="mainTab === 'market'">
|
|
249
|
-
统一管理 Codex / Claude Skills,并聚焦本地导入与分发。
|
|
250
|
-
</p>
|
|
251
|
-
</div>
|
|
317
|
+
<div class="main-panel-topbar">
|
|
318
|
+
<div class="panel-header panel-header-refined" v-if="!sessionStandalone">
|
|
319
|
+
<div class="panel-header-copy">
|
|
320
|
+
<div class="panel-kicker">{{ mainTabKicker }}</div>
|
|
321
|
+
<h1 class="main-title">{{ mainTabTitle }}</h1>
|
|
322
|
+
<p class="subtitle">{{ mainTabSubtitle }}</p>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
252
325
|
|
|
253
|
-
|
|
254
|
-
|
|
326
|
+
<div class="status-strip" v-if="!sessionStandalone && mainTab === 'config'">
|
|
327
|
+
<template v-if="isProviderConfigMode">
|
|
328
|
+
<div class="status-chip">
|
|
329
|
+
<span class="label">{{ activeProviderConfigChipLabel }}</span>
|
|
330
|
+
<span class="value">{{ currentProvider || t('common.notSelected') }}</span>
|
|
331
|
+
</div>
|
|
332
|
+
<div class="status-chip">
|
|
333
|
+
<span class="label">{{ activeProviderModelChipLabel }}</span>
|
|
334
|
+
<span class="value">{{ currentModel || t('common.notSelected') }}</span>
|
|
335
|
+
</div>
|
|
336
|
+
</template>
|
|
337
|
+
<template v-else-if="configMode === 'claude'">
|
|
338
|
+
<div class="status-chip">
|
|
339
|
+
<span class="label">{{ t('status.claudeConfig') }}</span>
|
|
340
|
+
<span class="value">{{ currentClaudeConfig || t('common.notSelected') }}</span>
|
|
341
|
+
</div>
|
|
342
|
+
<div class="status-chip">
|
|
343
|
+
<span class="label">{{ t('status.claudeModel') }}</span>
|
|
344
|
+
<span class="value">{{ currentClaudeModel || t('common.notSelected') }}</span>
|
|
345
|
+
</div>
|
|
346
|
+
</template>
|
|
347
|
+
<template v-else-if="configMode === 'openclaw'">
|
|
348
|
+
<div class="status-chip">
|
|
349
|
+
<span class="label">{{ t('status.openclawConfig') }}</span>
|
|
350
|
+
<span class="value">{{ currentOpenclawConfig || t('common.notSelected') }}</span>
|
|
351
|
+
</div>
|
|
352
|
+
<div class="status-chip">
|
|
353
|
+
<span class="label">{{ t('status.workspaceFile') }}</span>
|
|
354
|
+
<span class="value">{{ openclawWorkspaceFileName || t('common.notSelected') }}</span>
|
|
355
|
+
</div>
|
|
356
|
+
</template>
|
|
357
|
+
<template v-else>
|
|
358
|
+
<div class="status-chip">
|
|
359
|
+
<span class="label">{{ t('status.configMode') }}</span>
|
|
360
|
+
<span class="value">{{ t('common.notSelected') }}</span>
|
|
361
|
+
</div>
|
|
362
|
+
</template>
|
|
363
|
+
</div>
|
|
364
|
+
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'sessions'">
|
|
255
365
|
<div class="status-chip">
|
|
256
|
-
<span class="label">{{
|
|
257
|
-
<span class="value">
|
|
366
|
+
<span class="label">{{ t('status.currentSource') }}</span>
|
|
367
|
+
<span class="value">
|
|
368
|
+
{{ sessionFilterSource === 'all' ? t('sessions.source.all') : (sessionFilterSource === 'claude' ? 'Claude Code' : 'Codex') }}
|
|
369
|
+
</span>
|
|
258
370
|
</div>
|
|
259
371
|
<div class="status-chip">
|
|
260
|
-
<span class="label">{{
|
|
261
|
-
<span class="value">{{
|
|
372
|
+
<span class="label">{{ t('status.sessionCount') }}</span>
|
|
373
|
+
<span class="value">{{ sessionsList.length }}</span>
|
|
262
374
|
</div>
|
|
263
|
-
</
|
|
264
|
-
<
|
|
375
|
+
</div>
|
|
376
|
+
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'usage'">
|
|
265
377
|
<div class="status-chip">
|
|
266
|
-
<span class="label">
|
|
267
|
-
<span class="value">{{
|
|
378
|
+
<span class="label">{{ t('status.range') }}</span>
|
|
379
|
+
<span class="value">{{ sessionsUsageTimeRange === 'all' ? t('usage.range.all') : (sessionsUsageTimeRange === '30d' ? t('usage.range.30d.short') : t('usage.range.7d.short')) }}</span>
|
|
268
380
|
</div>
|
|
269
381
|
<div class="status-chip">
|
|
270
|
-
<span class="label">
|
|
271
|
-
<span class="value">{{
|
|
382
|
+
<span class="label">{{ t('status.totalSessions') }}</span>
|
|
383
|
+
<span class="value">{{ sessionUsageSummaryCards[0] ? sessionUsageSummaryCards[0].value : 0 }}</span>
|
|
272
384
|
</div>
|
|
273
|
-
</template>
|
|
274
|
-
<template v-else-if="configMode === 'openclaw'">
|
|
275
385
|
<div class="status-chip">
|
|
276
|
-
<span class="label">
|
|
277
|
-
<span class="value">{{
|
|
386
|
+
<span class="label">{{ t('status.totalMessages') }}</span>
|
|
387
|
+
<span class="value">{{ sessionUsageSummaryCards[1] ? sessionUsageSummaryCards[1].value : 0 }}</span>
|
|
278
388
|
</div>
|
|
389
|
+
</div>
|
|
390
|
+
<div class="status-strip" v-else-if="!sessionStandalone && taskOrchestrationTabEnabled && mainTab === 'orchestration'">
|
|
279
391
|
<div class="status-chip">
|
|
280
|
-
<span class="label"
|
|
281
|
-
<span class="value">{{
|
|
392
|
+
<span class="label">{{ t('status.engine') }}</span>
|
|
393
|
+
<span class="value">{{ taskOrchestration.selectedEngine === 'workflow' ? 'Workflow' : 'Codex' }}</span>
|
|
282
394
|
</div>
|
|
283
|
-
</template>
|
|
284
|
-
<template v-else>
|
|
285
395
|
<div class="status-chip">
|
|
286
|
-
<span class="label"
|
|
287
|
-
<span class="value"
|
|
396
|
+
<span class="label">{{ t('status.concurrency') }}</span>
|
|
397
|
+
<span class="value">{{ taskOrchestration.concurrency }}</span>
|
|
398
|
+
</div>
|
|
399
|
+
<div class="status-chip">
|
|
400
|
+
<span class="label">{{ t('status.running') }}</span>
|
|
401
|
+
<span class="value">{{ taskOrchestrationQueueStats.running }}</span>
|
|
402
|
+
</div>
|
|
403
|
+
<div class="status-chip">
|
|
404
|
+
<span class="label">{{ t('status.queued') }}</span>
|
|
405
|
+
<span class="value">{{ taskOrchestrationQueueStats.queued }}</span>
|
|
406
|
+
</div>
|
|
407
|
+
<div class="status-chip">
|
|
408
|
+
<span class="label">{{ t('status.runs') }}</span>
|
|
409
|
+
<span class="value">{{ taskOrchestration.runs.length }}</span>
|
|
288
410
|
</div>
|
|
289
|
-
</template>
|
|
290
|
-
</div>
|
|
291
|
-
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'sessions'">
|
|
292
|
-
<div class="status-chip">
|
|
293
|
-
<span class="label">当前来源</span>
|
|
294
|
-
<span class="value">
|
|
295
|
-
{{ sessionFilterSource === 'all' ? '全部' : (sessionFilterSource === 'claude' ? 'Claude Code' : 'Codex') }}
|
|
296
|
-
</span>
|
|
297
|
-
</div>
|
|
298
|
-
<div class="status-chip">
|
|
299
|
-
<span class="label">会话数</span>
|
|
300
|
-
<span class="value">{{ sessionsList.length }}</span>
|
|
301
|
-
</div>
|
|
302
|
-
</div>
|
|
303
|
-
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'market'">
|
|
304
|
-
<div class="status-chip">
|
|
305
|
-
<span class="label">当前目标</span>
|
|
306
|
-
<span class="value">{{ skillsTargetLabel }}</span>
|
|
307
411
|
</div>
|
|
308
|
-
<div class="status-
|
|
309
|
-
<
|
|
310
|
-
|
|
412
|
+
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'market'">
|
|
413
|
+
<div class="status-chip">
|
|
414
|
+
<span class="label">{{ t('status.currentTarget') }}</span>
|
|
415
|
+
<span class="value">{{ skillsTargetLabel }}</span>
|
|
416
|
+
</div>
|
|
417
|
+
<div class="status-chip">
|
|
418
|
+
<span class="label">{{ t('status.localSkills') }}</span>
|
|
419
|
+
<span class="value">{{ skillsList.length }}</span>
|
|
420
|
+
</div>
|
|
421
|
+
<div class="status-chip">
|
|
422
|
+
<span class="label">{{ t('status.importable') }}</span>
|
|
423
|
+
<span class="value">{{ skillsImportList.length }}</span>
|
|
424
|
+
</div>
|
|
425
|
+
<div class="status-chip">
|
|
426
|
+
<span class="label">{{ t('status.importableDirect') }}</span>
|
|
427
|
+
<span class="value">{{ skillsImportConfiguredCount }}</span>
|
|
428
|
+
</div>
|
|
311
429
|
</div>
|
|
312
|
-
<div class="status-
|
|
313
|
-
<
|
|
314
|
-
|
|
430
|
+
<div class="status-strip" v-else-if="!sessionStandalone && mainTab === 'docs'">
|
|
431
|
+
<div class="status-chip">
|
|
432
|
+
<span class="label">{{ t('status.pm') }}</span>
|
|
433
|
+
<span class="value">{{ String(installPackageManager || 'npm').toUpperCase() }}</span>
|
|
434
|
+
</div>
|
|
435
|
+
<div class="status-chip">
|
|
436
|
+
<span class="label">{{ t('status.action') }}</span>
|
|
437
|
+
<span class="value">{{ installCommandAction === 'update' ? t('common.update') : (installCommandAction === 'uninstall' ? t('common.uninstall') : t('common.install')) }}</span>
|
|
438
|
+
</div>
|
|
439
|
+
<div class="status-chip">
|
|
440
|
+
<span class="label">{{ t('status.registry') }}</span>
|
|
441
|
+
<span class="value">{{ installRegistryPreview || t('common.defaultOfficial') }}</span>
|
|
442
|
+
</div>
|
|
315
443
|
</div>
|
|
316
|
-
<div
|
|
317
|
-
|
|
318
|
-
|
|
444
|
+
<div
|
|
445
|
+
v-if="!sessionStandalone && mainTab === 'config' && isProviderConfigMode && forceCompactLayout && !loading && !initError && displayProvidersList.length > 1"
|
|
446
|
+
class="provider-fast-switch">
|
|
447
|
+
<label class="provider-fast-switch-label" for="provider-fast-switch-select">{{ t('status.quickSwitchProvider') }}</label>
|
|
448
|
+
<select
|
|
449
|
+
id="provider-fast-switch-select"
|
|
450
|
+
class="provider-fast-switch-select"
|
|
451
|
+
:value="displayCurrentProvider"
|
|
452
|
+
@change="quickSwitchProvider($event.target.value)">
|
|
453
|
+
<option v-for="provider in displayProvidersList" :key="'quick-switch-' + provider.name" :value="provider.name">
|
|
454
|
+
{{ provider.name }}
|
|
455
|
+
</option>
|
|
456
|
+
</select>
|
|
319
457
|
</div>
|
|
320
458
|
</div>
|
|
321
|
-
<div
|
|
322
|
-
v-if="!sessionStandalone && mainTab === 'config' && isProviderConfigMode && forceCompactLayout && !loading && !initError && displayProvidersList.length > 1"
|
|
323
|
-
class="provider-fast-switch">
|
|
324
|
-
<label class="provider-fast-switch-label" for="provider-fast-switch-select">快速切换提供商</label>
|
|
325
|
-
<select
|
|
326
|
-
id="provider-fast-switch-select"
|
|
327
|
-
class="provider-fast-switch-select"
|
|
328
|
-
:value="displayCurrentProvider"
|
|
329
|
-
@change="quickSwitchProvider($event.target.value)">
|
|
330
|
-
<option v-for="provider in displayProvidersList" :key="'quick-switch-' + provider.name" :value="provider.name">
|
|
331
|
-
{{ provider.name }}
|
|
332
|
-
</option>
|
|
333
|
-
</select>
|
|
334
|
-
</div>
|
|
335
459
|
|
|
336
460
|
<!-- 内容包裹器 - 稳定布局 -->
|
|
337
461
|
<div class="content-wrapper">
|