codexmate 0.0.22 → 0.0.23
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 +1 -0
- package/README.zh.md +4 -3
- package/package.json +1 -1
- package/web-ui/app.js +54 -3
- package/web-ui/modules/app.computed.main-tabs.mjs +6 -2
- package/web-ui/modules/app.methods.install.mjs +16 -0
- package/web-ui/modules/app.methods.navigation.mjs +43 -0
- package/web-ui/modules/app.methods.session-browser.mjs +66 -1
- package/web-ui/modules/app.methods.startup-claude.mjs +12 -0
- package/web-ui/modules/app.methods.task-orchestration.mjs +96 -11
- package/web-ui/modules/i18n.mjs +214 -0
- package/web-ui/modules/plugins.computed.mjs +2 -219
- package/web-ui/modules/plugins.methods.mjs +2 -619
- package/web-ui/modules/plugins.storage.mjs +11 -37
- package/web-ui/modules/sessions-filters-url.mjs +85 -0
- package/web-ui/partials/index/layout-header.html +2 -2
- package/web-ui/partials/index/panel-config-claude.html +21 -0
- package/web-ui/partials/index/panel-config-codex.html +21 -0
- package/web-ui/partials/index/panel-orchestration.html +102 -111
- package/web-ui/partials/index/panel-plugins.html +34 -4
- package/web-ui/partials/index/panel-sessions.html +9 -3
- package/web-ui/partials/index/panel-usage.html +5 -5
- package/web-ui/styles/controls-forms.css +7 -0
- package/web-ui/styles/layout-shell.css +9 -3
- package/web-ui/styles/navigation-panels.css +8 -0
- package/web-ui/styles/plugins-panel.css +5 -0
- package/web-ui/styles/sessions-usage.css +28 -0
- package/web-ui/styles/skills-market.css +12 -2
- package/web-ui/styles/task-orchestration.css +57 -11
|
@@ -8,23 +8,23 @@
|
|
|
8
8
|
<section class="selector-section task-hero-card">
|
|
9
9
|
<div class="task-hero-main">
|
|
10
10
|
<div>
|
|
11
|
-
<div class="task-hero-kicker">
|
|
12
|
-
<div class="selector-title"
|
|
13
|
-
<div class="skills-panel-note task-hero-copy"
|
|
11
|
+
<div class="task-hero-kicker">{{ t('orchestration.hero.kicker') }}</div>
|
|
12
|
+
<div class="selector-title">{{ t('orchestration.hero.title') }}</div>
|
|
13
|
+
<div class="skills-panel-note task-hero-copy">{{ t('orchestration.hero.subtitle') }}</div>
|
|
14
14
|
</div>
|
|
15
15
|
<div class="task-hero-actions settings-tab-actions task-header-actions">
|
|
16
16
|
<button type="button" class="btn-tool btn-tool-compact" @click="loadTaskOrchestrationOverview({ forceRefresh: true, includeDetail: true })" :disabled="taskOrchestration.loading">
|
|
17
|
-
{{ taskOrchestration.loading ? '
|
|
17
|
+
{{ taskOrchestration.loading ? t('common.refreshing') : t('common.refresh') }}
|
|
18
18
|
</button>
|
|
19
19
|
<button type="button" class="btn-tool btn-tool-compact" @click="resetTaskOrchestrationDraft()" :disabled="taskOrchestration.running || taskOrchestration.queueAdding || taskOrchestration.planning">
|
|
20
|
-
|
|
20
|
+
{{ t('orchestration.draft.reset') }}
|
|
21
21
|
</button>
|
|
22
22
|
</div>
|
|
23
23
|
</div>
|
|
24
|
-
<div v-if="taskOrchestrationQueueStats.running || taskOrchestrationQueueStats.queued || taskOrchestration.runs.length" class="task-hero-meta-strip" aria-label="
|
|
25
|
-
<div class="task-hero-meta"
|
|
26
|
-
<div class="task-hero-meta"
|
|
27
|
-
<div class="task-hero-meta"
|
|
24
|
+
<div v-if="taskOrchestrationQueueStats.running || taskOrchestrationQueueStats.queued || taskOrchestration.runs.length" class="task-hero-meta-strip" :aria-label="t('orchestration.summary.aria')">
|
|
25
|
+
<div class="task-hero-meta">{{ t('orchestration.summary.running') }} <strong>{{ taskOrchestrationQueueStats.running }}</strong></div>
|
|
26
|
+
<div class="task-hero-meta">{{ t('orchestration.summary.queued') }} <strong>{{ taskOrchestrationQueueStats.queued }}</strong></div>
|
|
27
|
+
<div class="task-hero-meta">{{ t('orchestration.summary.runs') }} <strong>{{ taskOrchestration.runs.length }}</strong></div>
|
|
28
28
|
</div>
|
|
29
29
|
</section>
|
|
30
30
|
|
|
@@ -34,27 +34,27 @@
|
|
|
34
34
|
<div class="task-flow-head">
|
|
35
35
|
<div class="task-flow-step">1</div>
|
|
36
36
|
<div>
|
|
37
|
-
<div class="task-flow-title"
|
|
38
|
-
<div class="task-flow-copy"
|
|
37
|
+
<div class="task-flow-title">{{ t('orchestration.step1.title') }}</div>
|
|
38
|
+
<div class="task-flow-copy">{{ t('orchestration.step1.subtitle') }}</div>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
41
41
|
|
|
42
42
|
<details v-if="!taskOrchestration.target.trim()" class="task-template-panel">
|
|
43
|
-
<summary class="task-advanced-summary"
|
|
43
|
+
<summary class="task-advanced-summary">{{ t('orchestration.templates.title') }}</summary>
|
|
44
44
|
<div class="task-template-block">
|
|
45
45
|
<div class="task-template-chip-group">
|
|
46
|
-
<button type="button" class="task-template-chip" @click="taskOrchestration.target = '
|
|
47
|
-
<button type="button" class="task-template-chip" @click="taskOrchestration.target = '
|
|
48
|
-
<button type="button" class="task-template-chip" @click="taskOrchestration.target = '
|
|
46
|
+
<button type="button" class="task-template-chip" @click="taskOrchestration.target = t('orchestration.templates.reviewFix.target'); taskOrchestration.selectedEngine = 'codex'; taskOrchestration.workflowIdsText = ''; taskOrchestration.notes = t('orchestration.templates.reviewFix.notes'); taskOrchestration.followUpsText = t('orchestration.templates.reviewFix.followUps')">{{ t('orchestration.templates.reviewFix.label') }}</button>
|
|
47
|
+
<button type="button" class="task-template-chip" @click="taskOrchestration.target = t('orchestration.templates.planOnly.target'); taskOrchestration.selectedEngine = 'codex'; taskOrchestration.workflowIdsText = ''; taskOrchestration.notes = t('orchestration.templates.planOnly.notes'); taskOrchestration.followUpsText = ''">{{ t('orchestration.templates.planOnly.label') }}</button>
|
|
48
|
+
<button type="button" class="task-template-chip" @click="taskOrchestration.target = t('orchestration.templates.workflowBatch.target'); taskOrchestration.selectedEngine = 'workflow'; taskOrchestration.workflowIdsText = t('orchestration.templates.workflowBatch.workflowIds'); taskOrchestration.notes = t('orchestration.templates.workflowBatch.notes'); taskOrchestration.followUpsText = ''">{{ t('orchestration.templates.workflowBatch.label') }}</button>
|
|
49
49
|
</div>
|
|
50
50
|
</div>
|
|
51
51
|
</details>
|
|
52
52
|
|
|
53
53
|
<div class="selector-grid task-composer-grid task-composer-grid-primary">
|
|
54
54
|
<label class="selector-field task-field task-field-wide task-goal-field">
|
|
55
|
-
<span class="selector-label"
|
|
56
|
-
<textarea v-model="taskOrchestration.target" class="task-textarea task-textarea-goal" rows="5" placeholder="
|
|
57
|
-
<span class="task-field-hint"
|
|
55
|
+
<span class="selector-label">{{ t('orchestration.fields.target') }}</span>
|
|
56
|
+
<textarea v-model="taskOrchestration.target" class="task-textarea task-textarea-goal" rows="5" :placeholder="t('orchestration.fields.target.placeholder')"></textarea>
|
|
57
|
+
<span class="task-field-hint">{{ t('orchestration.fields.target.hint') }}</span>
|
|
58
58
|
</label>
|
|
59
59
|
</div>
|
|
60
60
|
|
|
@@ -64,12 +64,11 @@
|
|
|
64
64
|
<div class="task-readiness-copy task-draft-inline-copy">{{ taskOrchestrationDraftReadiness.summary }}</div>
|
|
65
65
|
</div>
|
|
66
66
|
<div class="task-config-strip">
|
|
67
|
-
<div class="task-config-pill">{{ taskOrchestration.selectedEngine === 'workflow' ? '
|
|
68
|
-
<div class="task-config-pill">{{ taskOrchestration.
|
|
69
|
-
<div class="task-config-pill">{{
|
|
70
|
-
<div v-if="taskOrchestration.
|
|
71
|
-
<div v-if="taskOrchestration.
|
|
72
|
-
<div v-if="taskOrchestration.plan" class="task-config-pill">计划 {{ taskOrchestrationDraftMetrics.planNodeCount }} 节点</div>
|
|
67
|
+
<div class="task-config-pill">{{ taskOrchestration.selectedEngine === 'workflow' ? t('orchestration.engine.workflow') : t('orchestration.engine.codex') }}</div>
|
|
68
|
+
<div class="task-config-pill">{{ taskOrchestration.runMode === 'dry-run' ? t('orchestration.runMode.dryRun') : (taskOrchestration.runMode === 'read' ? t('orchestration.runMode.readOnly') : t('orchestration.runMode.write')) }}</div>
|
|
69
|
+
<div v-if="taskOrchestration.title.trim()" class="task-config-pill">{{ t('orchestration.pills.hasTitle') }}</div>
|
|
70
|
+
<div v-if="taskOrchestration.selectedEngine === 'workflow' && taskOrchestrationDraftMetrics.workflowCount > 0" class="task-config-pill">{{ t('orchestration.pills.workflowCount', { count: taskOrchestrationDraftMetrics.workflowCount }) }}</div>
|
|
71
|
+
<div v-if="taskOrchestration.plan" class="task-config-pill">{{ t('orchestration.pills.planNodes', { count: taskOrchestrationDraftMetrics.planNodeCount }) }}</div>
|
|
73
72
|
</div>
|
|
74
73
|
</div>
|
|
75
74
|
</div>
|
|
@@ -78,64 +77,59 @@
|
|
|
78
77
|
<div class="task-flow-head">
|
|
79
78
|
<div class="task-flow-step">2</div>
|
|
80
79
|
<div>
|
|
81
|
-
<div class="task-flow-title"
|
|
82
|
-
<div class="task-flow-copy"
|
|
80
|
+
<div class="task-flow-title">{{ t('orchestration.step2.title') }}</div>
|
|
81
|
+
<div class="task-flow-copy">{{ t('orchestration.step2.subtitle') }}</div>
|
|
83
82
|
</div>
|
|
84
83
|
</div>
|
|
85
84
|
|
|
86
|
-
<div class="selector-grid task-composer-grid task-composer-grid-compact">
|
|
85
|
+
<div class="selector-grid task-composer-grid task-composer-grid-compact task-composer-grid-inline">
|
|
87
86
|
<label class="selector-field">
|
|
88
|
-
<span class="selector-label"
|
|
89
|
-
<select v-model="taskOrchestration.selectedEngine">
|
|
90
|
-
<option value="codex">
|
|
91
|
-
<option value="workflow">
|
|
87
|
+
<span class="selector-label">{{ t('orchestration.fields.engine') }}</span>
|
|
88
|
+
<select v-model="taskOrchestration.selectedEngine" class="provider-fast-switch-select" disabled>
|
|
89
|
+
<option value="codex">{{ t('orchestration.engine.codex') }}</option>
|
|
90
|
+
<option value="workflow">{{ t('orchestration.engine.workflow') }}</option>
|
|
91
|
+
</select>
|
|
92
|
+
</label>
|
|
93
|
+
<label class="selector-field">
|
|
94
|
+
<span class="selector-label">{{ t('orchestration.fields.runMode') }}</span>
|
|
95
|
+
<select v-model="taskOrchestration.runMode" class="provider-fast-switch-select" disabled>
|
|
96
|
+
<option value="write">{{ t('orchestration.runMode.write') }}</option>
|
|
97
|
+
<option value="read">{{ t('orchestration.runMode.readOnly') }}</option>
|
|
98
|
+
<option value="dry-run">{{ t('orchestration.runMode.dryRun') }}</option>
|
|
92
99
|
</select>
|
|
93
100
|
</label>
|
|
94
|
-
<div class="selector-field task-toggle-card task-toggle-card-inline">
|
|
95
|
-
<span class="selector-label">运行模式</span>
|
|
96
|
-
<div class="task-toggle-inline">
|
|
97
|
-
<label class="task-toggle">
|
|
98
|
-
<input v-model="taskOrchestration.allowWrite" type="checkbox">
|
|
99
|
-
<span>允许写入</span>
|
|
100
|
-
</label>
|
|
101
|
-
<label class="task-toggle">
|
|
102
|
-
<input v-model="taskOrchestration.dryRun" type="checkbox">
|
|
103
|
-
<span>仅预演</span>
|
|
104
|
-
</label>
|
|
105
|
-
</div>
|
|
106
|
-
</div>
|
|
107
101
|
</div>
|
|
108
102
|
|
|
109
103
|
<details class="task-advanced-panel">
|
|
110
|
-
<summary class="task-advanced-summary"
|
|
104
|
+
<summary class="task-advanced-summary">{{ t('orchestration.advanced.title') }}</summary>
|
|
111
105
|
<div class="selector-grid task-composer-grid task-composer-grid-secondary">
|
|
112
106
|
<label class="selector-field task-field-wide">
|
|
113
|
-
<span class="selector-label"
|
|
114
|
-
<input v-model="taskOrchestration.title" type="text" placeholder="
|
|
107
|
+
<span class="selector-label">{{ t('orchestration.fields.title') }}</span>
|
|
108
|
+
<input v-model="taskOrchestration.title" class="model-input" type="text" :placeholder="t('orchestration.fields.title.placeholder')">
|
|
115
109
|
</label>
|
|
116
110
|
<label class="selector-field task-field-wide">
|
|
117
|
-
<span class="selector-label"
|
|
118
|
-
<textarea v-model="taskOrchestration.notes" class="task-textarea" rows="3" placeholder="
|
|
119
|
-
<span class="task-field-hint"
|
|
111
|
+
<span class="selector-label">{{ t('orchestration.fields.notes') }}</span>
|
|
112
|
+
<textarea v-model="taskOrchestration.notes" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.notes.placeholder')"></textarea>
|
|
113
|
+
<span class="task-field-hint">{{ t('orchestration.fields.notes.hint') }}</span>
|
|
120
114
|
</label>
|
|
121
115
|
<label class="selector-field task-field-wide">
|
|
122
|
-
<span class="selector-label"
|
|
123
|
-
<textarea v-model="taskOrchestration.followUpsText" class="task-textarea" rows="3" placeholder="
|
|
116
|
+
<span class="selector-label">{{ t('orchestration.fields.followUps') }}</span>
|
|
117
|
+
<textarea v-model="taskOrchestration.followUpsText" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.followUps.placeholder')"></textarea>
|
|
124
118
|
</label>
|
|
125
119
|
<label class="selector-field">
|
|
126
|
-
<span class="selector-label"
|
|
127
|
-
<input v-model="taskOrchestration.concurrency" type="number" min="1" max="8">
|
|
128
|
-
<span class="task-field-hint"
|
|
120
|
+
<span class="selector-label">{{ t('orchestration.fields.concurrency') }}</span>
|
|
121
|
+
<input v-model="taskOrchestration.concurrency" class="model-input" type="number" min="1" max="8">
|
|
122
|
+
<span class="task-field-hint">{{ t('orchestration.fields.concurrency.hint') }}</span>
|
|
129
123
|
</label>
|
|
130
124
|
<label class="selector-field">
|
|
131
|
-
<span class="selector-label"
|
|
132
|
-
<input v-model="taskOrchestration.autoFixRounds" type="number" min="0" max="5">
|
|
133
|
-
<span class="task-field-hint"
|
|
125
|
+
<span class="selector-label">{{ t('orchestration.fields.autoFixRounds') }}</span>
|
|
126
|
+
<input v-model="taskOrchestration.autoFixRounds" class="model-input" type="number" min="0" max="5">
|
|
127
|
+
<span class="task-field-hint">{{ t('orchestration.fields.autoFixRounds.hint') }}</span>
|
|
134
128
|
</label>
|
|
135
129
|
<label v-if="taskOrchestration.selectedEngine === 'workflow'" class="selector-field task-field-wide">
|
|
136
|
-
<span class="selector-label">
|
|
137
|
-
<textarea v-model="taskOrchestration.workflowIdsText" class="task-textarea" rows="3" placeholder="
|
|
138
|
-
<span class="task-field-hint"
|
|
130
|
+
<span class="selector-label">{{ t('orchestration.fields.workflowIds') }}</span>
|
|
131
|
+
<textarea v-model="taskOrchestration.workflowIdsText" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.workflowIds.placeholder')"></textarea>
|
|
132
|
+
<span class="task-field-hint">{{ t('orchestration.fields.workflowIds.hint', { count: taskOrchestration.workflows.length }) }}</span>
|
|
139
133
|
<div v-if="taskOrchestration.workflows.length" class="task-workflow-suggestions">
|
|
140
134
|
<button
|
|
141
135
|
v-for="workflow in taskOrchestration.workflows"
|
|
@@ -144,7 +138,7 @@
|
|
|
144
138
|
class="task-workflow-chip"
|
|
145
139
|
@click="appendTaskWorkflowId(workflow.id || workflow.name)">
|
|
146
140
|
<span>{{ workflow.name || workflow.id }}</span>
|
|
147
|
-
<small v-if="workflow.stepCount">{{ workflow.stepCount }}
|
|
141
|
+
<small v-if="workflow.stepCount">{{ t('orchestration.workflow.stepCount', { count: workflow.stepCount }) }}</small>
|
|
148
142
|
</button>
|
|
149
143
|
</div>
|
|
150
144
|
</label>
|
|
@@ -156,27 +150,24 @@
|
|
|
156
150
|
<div class="task-flow-head">
|
|
157
151
|
<div class="task-flow-step">3</div>
|
|
158
152
|
<div>
|
|
159
|
-
<div class="task-flow-title"
|
|
160
|
-
<div class="task-flow-copy"
|
|
153
|
+
<div class="task-flow-title">{{ t('orchestration.step3.title') }}</div>
|
|
154
|
+
<div class="task-flow-copy">{{ t('orchestration.step3.subtitle') }}</div>
|
|
161
155
|
</div>
|
|
162
156
|
</div>
|
|
163
157
|
<div class="task-action-row task-action-row-prominent">
|
|
164
158
|
<button type="button" class="btn-tool task-action-preview" @click="previewTaskPlan()" :disabled="taskOrchestration.planning || taskOrchestration.running || !taskOrchestration.target.trim()">
|
|
165
|
-
{{ taskOrchestration.planning ? '
|
|
159
|
+
{{ taskOrchestration.planning ? t('orchestration.actions.planning') : t('orchestration.actions.previewOnly') }}
|
|
166
160
|
</button>
|
|
167
161
|
<div class="task-action-row-right task-action-row-right-prominent">
|
|
168
|
-
<button type="button" class="btn-tool btn-primary" @click="
|
|
169
|
-
{{ taskOrchestration.running ? '
|
|
170
|
-
</button>
|
|
171
|
-
<button type="button" class="btn-tool" @click="addTaskOrchestrationToQueue()" :disabled="taskOrchestration.queueAdding || !taskOrchestration.target.trim()">
|
|
172
|
-
{{ taskOrchestration.queueAdding ? '加入中...' : '加入队列' }}
|
|
162
|
+
<button type="button" class="btn-tool btn-primary" @click="planAndRunTaskOrchestration()" :disabled="taskOrchestration.running || taskOrchestration.planning || !taskOrchestration.target.trim()">
|
|
163
|
+
{{ (taskOrchestration.running || taskOrchestration.planning) ? t('orchestration.actions.preparing') : (taskOrchestration.runMode === 'dry-run' ? t('orchestration.actions.generatePlan') : t('orchestration.actions.planAndRun')) }}
|
|
173
164
|
</button>
|
|
174
|
-
<button
|
|
175
|
-
{{ taskOrchestration.queueStarting ? '
|
|
165
|
+
<button type="button" class="btn-tool" @click="queueTaskOrchestrationAndStart()" :disabled="taskOrchestration.queueAdding || taskOrchestration.queueStarting || taskOrchestration.planning || !taskOrchestration.target.trim()">
|
|
166
|
+
{{ (taskOrchestration.queueAdding || taskOrchestration.queueStarting) ? t('orchestration.actions.processing') : t('orchestration.actions.queueAndStart') }}
|
|
176
167
|
</button>
|
|
177
168
|
</div>
|
|
178
169
|
</div>
|
|
179
|
-
<div class="task-action-caption"
|
|
170
|
+
<div class="task-action-caption">{{ t('orchestration.actions.caption') }}</div>
|
|
180
171
|
</div>
|
|
181
172
|
</section>
|
|
182
173
|
</div>
|
|
@@ -186,13 +177,13 @@
|
|
|
186
177
|
class="selector-section task-stage-card">
|
|
187
178
|
<div class="task-stage-empty">
|
|
188
179
|
<div>
|
|
189
|
-
<div class="selector-title"
|
|
190
|
-
<div class="skills-panel-note"
|
|
180
|
+
<div class="selector-title">{{ t('orchestration.stage.title') }}</div>
|
|
181
|
+
<div class="skills-panel-note">{{ t('orchestration.stage.subtitle') }}</div>
|
|
191
182
|
</div>
|
|
192
183
|
<div class="task-stage-strip">
|
|
193
|
-
<div class="task-stage-pill"
|
|
194
|
-
<div class="task-stage-pill"
|
|
195
|
-
<div class="task-stage-pill"
|
|
184
|
+
<div class="task-stage-pill">{{ t('orchestration.stage.pill.target') }}</div>
|
|
185
|
+
<div class="task-stage-pill">{{ t('orchestration.stage.pill.preview') }}</div>
|
|
186
|
+
<div class="task-stage-pill">{{ t('orchestration.stage.pill.run') }}</div>
|
|
196
187
|
</div>
|
|
197
188
|
</div>
|
|
198
189
|
</section>
|
|
@@ -206,8 +197,8 @@
|
|
|
206
197
|
<div v-if="taskOrchestration.lastError" class="task-issue-item">{{ taskOrchestration.lastError }}</div>
|
|
207
198
|
<div class="selector-header task-section-header">
|
|
208
199
|
<div>
|
|
209
|
-
<span class="selector-title"
|
|
210
|
-
<div class="skills-panel-note"
|
|
200
|
+
<span class="selector-title">{{ t('orchestration.plan.title') }}</span>
|
|
201
|
+
<div class="skills-panel-note">{{ t('orchestration.plan.subtitle') }}</div>
|
|
211
202
|
</div>
|
|
212
203
|
</div>
|
|
213
204
|
<div v-if="taskOrchestration.planIssues.length" class="task-issues-list">
|
|
@@ -223,15 +214,15 @@
|
|
|
223
214
|
<template v-if="taskOrchestration.plan">
|
|
224
215
|
<div class="task-plan-summary-strip">
|
|
225
216
|
<div class="task-plan-summary-item">
|
|
226
|
-
<span class="task-plan-summary-label"
|
|
217
|
+
<span class="task-plan-summary-label">{{ t('orchestration.plan.summary.nodes') }}</span>
|
|
227
218
|
<strong>{{ taskOrchestration.plan.nodes.length }}</strong>
|
|
228
219
|
</div>
|
|
229
220
|
<div class="task-plan-summary-item">
|
|
230
|
-
<span class="task-plan-summary-label"
|
|
221
|
+
<span class="task-plan-summary-label">{{ t('orchestration.plan.summary.waves') }}</span>
|
|
231
222
|
<strong>{{ taskOrchestration.plan.waves.length }}</strong>
|
|
232
223
|
</div>
|
|
233
224
|
<div class="task-plan-summary-item">
|
|
234
|
-
<span class="task-plan-summary-label"
|
|
225
|
+
<span class="task-plan-summary-label">{{ t('orchestration.plan.summary.engine') }}</span>
|
|
235
226
|
<strong>{{ taskOrchestration.plan.engine }}</strong>
|
|
236
227
|
</div>
|
|
237
228
|
</div>
|
|
@@ -248,9 +239,9 @@
|
|
|
248
239
|
<div class="task-node-title">{{ node.title || node.id }}</div>
|
|
249
240
|
<div class="task-node-meta">{{ node.id }} · {{ node.kind }}<span v-if="node.workflowId"> · {{ node.workflowId }}</span></div>
|
|
250
241
|
</div>
|
|
251
|
-
<span :class="['pill', node.write ? 'configured' : 'empty']">{{ node.write ? 'write' : '
|
|
242
|
+
<span :class="['pill', node.write ? 'configured' : 'empty']">{{ node.write ? t('orchestration.plan.node.write') : t('orchestration.plan.node.readOnly') }}</span>
|
|
252
243
|
</div>
|
|
253
|
-
<div class="task-node-deps"
|
|
244
|
+
<div class="task-node-deps">{{ t('orchestration.labels.dependencies') }}{{ formatTaskNodeDependencies(node) }}</div>
|
|
254
245
|
</div>
|
|
255
246
|
</div>
|
|
256
247
|
</template>
|
|
@@ -261,15 +252,15 @@
|
|
|
261
252
|
class="selector-section task-workbench-card">
|
|
262
253
|
<div class="selector-header task-section-header">
|
|
263
254
|
<div>
|
|
264
|
-
<span class="selector-title"
|
|
265
|
-
<div class="skills-panel-note"
|
|
255
|
+
<span class="selector-title">{{ t('orchestration.workbench.title') }}</span>
|
|
256
|
+
<div class="skills-panel-note">{{ t('orchestration.workbench.subtitle') }}</div>
|
|
266
257
|
</div>
|
|
267
258
|
<div class="settings-tab-actions task-header-actions">
|
|
268
259
|
<button type="button" class="btn-tool btn-tool-compact" @click="loadTaskOrchestrationOverview({ forceRefresh: true, includeDetail: true })" :disabled="taskOrchestration.loading">
|
|
269
|
-
{{ taskOrchestration.loading ? '
|
|
260
|
+
{{ taskOrchestration.loading ? t('common.refreshing') : t('common.refresh') }}
|
|
270
261
|
</button>
|
|
271
262
|
<button v-if="taskOrchestration.queue.length" type="button" class="btn-tool btn-tool-compact" @click="startTaskQueueRunner()" :disabled="taskOrchestration.queueStarting">
|
|
272
|
-
{{ taskOrchestration.queueStarting ? '
|
|
263
|
+
{{ taskOrchestration.queueStarting ? t('orchestration.queue.starting') : t('orchestration.queue.start') }}
|
|
273
264
|
</button>
|
|
274
265
|
</div>
|
|
275
266
|
</div>
|
|
@@ -278,16 +269,16 @@
|
|
|
278
269
|
v-if="(taskOrchestration.queue.length ? 1 : 0) + (taskOrchestration.runs.length ? 1 : 0) + ((taskOrchestration.selectedRunId || taskOrchestration.selectedRunError) ? 1 : 0) > 1"
|
|
279
270
|
class="task-workbench-tabs"
|
|
280
271
|
role="group"
|
|
281
|
-
aria-label="
|
|
282
|
-
<button v-if="taskOrchestration.queue.length" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'queue' }" @click="taskOrchestration.workspaceTab = 'queue'"
|
|
283
|
-
<button v-if="taskOrchestration.runs.length" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'runs' }" @click="taskOrchestration.workspaceTab = 'runs'"
|
|
284
|
-
<button v-if="taskOrchestration.selectedRunId || taskOrchestration.selectedRunError" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'detail' }" @click="taskOrchestration.workspaceTab = 'detail'"
|
|
272
|
+
:aria-label="t('orchestration.workbench.tabs.aria')">
|
|
273
|
+
<button v-if="taskOrchestration.queue.length" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'queue' }" @click="taskOrchestration.workspaceTab = 'queue'">{{ t('orchestration.workbench.tabs.queue', { count: taskOrchestration.queue.length }) }}</button>
|
|
274
|
+
<button v-if="taskOrchestration.runs.length" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'runs' }" @click="taskOrchestration.workspaceTab = 'runs'">{{ t('orchestration.workbench.tabs.runs', { count: taskOrchestration.runs.length }) }}</button>
|
|
275
|
+
<button v-if="taskOrchestration.selectedRunId || taskOrchestration.selectedRunError" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'detail' }" @click="taskOrchestration.workspaceTab = 'detail'">{{ t('orchestration.workbench.tabs.detail') }}</button>
|
|
285
276
|
</div>
|
|
286
277
|
|
|
287
278
|
<div v-if="taskOrchestration.workspaceTab === 'queue' || (!taskOrchestration.runs.length && !taskOrchestration.selectedRunId && !taskOrchestration.selectedRunError)" class="task-workbench-panel">
|
|
288
279
|
<div v-if="!taskOrchestration.queue.length" class="task-empty-state">
|
|
289
|
-
<div class="task-empty-title"
|
|
290
|
-
<div class="task-empty-copy"
|
|
280
|
+
<div class="task-empty-title">{{ t('orchestration.queue.empty.title') }}</div>
|
|
281
|
+
<div class="task-empty-copy">{{ t('orchestration.queue.empty.subtitle') }}</div>
|
|
291
282
|
</div>
|
|
292
283
|
<div v-else class="task-runtime-list">
|
|
293
284
|
<div
|
|
@@ -307,7 +298,7 @@
|
|
|
307
298
|
</div>
|
|
308
299
|
<div class="task-runtime-item-actions">
|
|
309
300
|
<span :class="['pill', taskRunStatusTone(item.status)]">{{ item.status }}</span>
|
|
310
|
-
<button type="button" class="btn-mini" @click.stop="cancelTaskRunFromUi(item.taskId)" :disabled="item.status !== 'queued' && item.status !== 'running'"
|
|
301
|
+
<button type="button" class="btn-mini" @click.stop="cancelTaskRunFromUi(item.taskId)" :disabled="item.status !== 'queued' && item.status !== 'running'">{{ t('common.cancel') }}</button>
|
|
311
302
|
</div>
|
|
312
303
|
</div>
|
|
313
304
|
</div>
|
|
@@ -315,8 +306,8 @@
|
|
|
315
306
|
|
|
316
307
|
<div v-else-if="taskOrchestration.workspaceTab === 'runs' || (!taskOrchestration.queue.length && taskOrchestration.runs.length && !taskOrchestration.selectedRunId && !taskOrchestration.selectedRunError)" class="task-workbench-panel">
|
|
317
308
|
<div v-if="!taskOrchestration.runs.length" class="task-empty-state">
|
|
318
|
-
<div class="task-empty-title"
|
|
319
|
-
<div class="task-empty-copy"
|
|
309
|
+
<div class="task-empty-title">{{ t('orchestration.runs.empty.title') }}</div>
|
|
310
|
+
<div class="task-empty-copy">{{ t('orchestration.runs.empty.subtitle') }}</div>
|
|
320
311
|
</div>
|
|
321
312
|
<div v-else class="task-runtime-list">
|
|
322
313
|
<button
|
|
@@ -340,38 +331,38 @@
|
|
|
340
331
|
<div v-else class="task-workbench-panel">
|
|
341
332
|
<div class="task-detail-toolbar settings-tab-actions">
|
|
342
333
|
<button type="button" class="btn-tool btn-tool-compact" @click="taskOrchestration.selectedRunId ? loadTaskRunDetail(taskOrchestration.selectedRunId) : null" :disabled="!taskOrchestration.selectedRunId || taskOrchestration.selectedRunLoading">
|
|
343
|
-
{{ taskOrchestration.selectedRunLoading ? '
|
|
334
|
+
{{ taskOrchestration.selectedRunLoading ? t('common.refreshing') : t('orchestration.detail.refresh') }}
|
|
344
335
|
</button>
|
|
345
336
|
<button type="button" class="btn-tool btn-tool-compact" @click="retryTaskRunFromUi(taskOrchestration.selectedRunId)" :disabled="!taskOrchestration.selectedRunId || taskOrchestration.retrying">
|
|
346
|
-
{{ taskOrchestration.retrying ? '
|
|
337
|
+
{{ taskOrchestration.retrying ? t('orchestration.detail.retrying') : t('orchestration.detail.retry') }}
|
|
347
338
|
</button>
|
|
348
339
|
<button type="button" class="btn-tool btn-tool-compact" @click="cancelTaskRunFromUi(taskOrchestration.selectedRunId)" :disabled="!taskOrchestrationSelectedRun || !taskOrchestrationSelectedRun.run || !isTaskRunActive(taskOrchestrationSelectedRun.run.status)">
|
|
349
|
-
|
|
340
|
+
{{ t('common.cancel') }}
|
|
350
341
|
</button>
|
|
351
342
|
</div>
|
|
352
343
|
|
|
353
344
|
<div v-if="taskOrchestration.selectedRunError" class="task-issue-item">{{ taskOrchestration.selectedRunError }}</div>
|
|
354
345
|
<div v-if="!taskOrchestrationSelectedRun" class="task-empty-state">
|
|
355
|
-
<div class="task-empty-title"
|
|
356
|
-
<div class="task-empty-copy"
|
|
346
|
+
<div class="task-empty-title">{{ t('orchestration.detail.empty.title') }}</div>
|
|
347
|
+
<div class="task-empty-copy">{{ t('orchestration.detail.empty.subtitle') }}</div>
|
|
357
348
|
</div>
|
|
358
349
|
<template v-else>
|
|
359
350
|
<div class="task-detail-summary-strip">
|
|
360
351
|
<div class="task-plan-summary-item">
|
|
361
|
-
<span class="task-plan-summary-label"
|
|
352
|
+
<span class="task-plan-summary-label">{{ t('orchestration.detail.summary.status') }}</span>
|
|
362
353
|
<strong>{{ taskOrchestrationSelectedRun.run.status }}</strong>
|
|
363
354
|
</div>
|
|
364
355
|
<div class="task-plan-summary-item">
|
|
365
|
-
<span class="task-plan-summary-label"
|
|
356
|
+
<span class="task-plan-summary-label">{{ t('orchestration.detail.summary.duration') }}</span>
|
|
366
357
|
<strong>{{ taskOrchestrationSelectedRun.run.durationMs || 0 }}ms</strong>
|
|
367
358
|
</div>
|
|
368
359
|
<div class="task-plan-summary-item">
|
|
369
|
-
<span class="task-plan-summary-label"
|
|
360
|
+
<span class="task-plan-summary-label">{{ t('orchestration.detail.summary.nodes') }}</span>
|
|
370
361
|
<strong>{{ taskOrchestrationSelectedRunNodes.length }}</strong>
|
|
371
362
|
</div>
|
|
372
363
|
<div class="task-plan-summary-item">
|
|
373
|
-
<span class="task-plan-summary-label"
|
|
374
|
-
<strong>{{ taskOrchestrationSelectedRun.run.summary || '
|
|
364
|
+
<span class="task-plan-summary-label">{{ t('orchestration.detail.summary.summary') }}</span>
|
|
365
|
+
<strong>{{ taskOrchestrationSelectedRun.run.summary || t('common.none') }}</strong>
|
|
375
366
|
</div>
|
|
376
367
|
</div>
|
|
377
368
|
<div v-if="taskOrchestrationSelectedRun.run.error" class="task-issue-item">{{ taskOrchestrationSelectedRun.run.error }}</div>
|
|
@@ -380,13 +371,13 @@
|
|
|
380
371
|
<div class="task-node-head">
|
|
381
372
|
<div>
|
|
382
373
|
<div class="task-node-title">{{ node.title || node.id }}</div>
|
|
383
|
-
<div class="task-node-meta">{{ node.id
|
|
374
|
+
<div class="task-node-meta">{{ t('orchestration.detail.node.meta', { id: node.id, attempts: (node.attemptCount || 0), autoFix: (node.autoFixRounds || 0) }) }}</div>
|
|
384
375
|
</div>
|
|
385
376
|
<span :class="['pill', taskRunStatusTone(node.status)]">{{ node.status }}</span>
|
|
386
377
|
</div>
|
|
387
378
|
<div v-if="node.summary" class="task-runtime-item-summary">{{ node.summary }}</div>
|
|
388
|
-
<div v-if="node.error && node.error !== node.summary" class="task-node-deps"
|
|
389
|
-
<div class="task-node-deps"
|
|
379
|
+
<div v-if="node.error && node.error !== node.summary" class="task-node-deps">{{ t('orchestration.labels.error') }}{{ node.error }}</div>
|
|
380
|
+
<div class="task-node-deps">{{ t('orchestration.labels.dependencies') }}{{ formatTaskNodeDependencies(node) }}</div>
|
|
390
381
|
<pre class="task-log-block">{{ formatTaskNodeLogs(node.logs) }}</pre>
|
|
391
382
|
</div>
|
|
392
383
|
</div>
|
|
@@ -37,7 +37,12 @@
|
|
|
37
37
|
</aside>
|
|
38
38
|
|
|
39
39
|
<section class="plugins-main" :aria-label="t('plugins.main.ariaWorkspace')">
|
|
40
|
-
<div v-if="
|
|
40
|
+
<div v-if="pluginsLoading" class="skills-empty-state">{{ t('common.loading') }}</div>
|
|
41
|
+
<div v-else-if="pluginsError" class="skills-empty-state">
|
|
42
|
+
<div class="plugins-panel-note">{{ pluginsError }}</div>
|
|
43
|
+
<button type="button" class="btn-mini" @click="loadPluginsOverview({ forceRefresh: true, silent: false })" :disabled="loading || !!initError || pluginsLoading">{{ t('common.refresh') }}</button>
|
|
44
|
+
</div>
|
|
45
|
+
<div v-else-if="pluginsActiveId === 'prompt-templates'" class="plugins-panel">
|
|
41
46
|
<div class="plugins-panel-head">
|
|
42
47
|
<div class="plugins-panel-title">{{ t('plugins.promptTemplates.title') }}</div>
|
|
43
48
|
<div class="plugins-panel-subtitle">{{ t('plugins.promptTemplates.subtitle') }}</div>
|
|
@@ -78,8 +83,8 @@
|
|
|
78
83
|
</select>
|
|
79
84
|
|
|
80
85
|
<div v-if="!promptComposerActiveTemplate" class="plugins-panel-note">{{ t('plugins.promptTemplates.compose.empty') }}</div>
|
|
81
|
-
<div v-else class="plugins-panel-note">{{ t('plugins.promptTemplates.compose.varsHint') }}</div>
|
|
82
|
-
<div class="prompt-compose-actions">
|
|
86
|
+
<div v-else-if="!promptComposerActiveTemplate.isBuiltin" class="plugins-panel-note">{{ t('plugins.promptTemplates.compose.varsHint') }}</div>
|
|
87
|
+
<div v-if="promptComposerActiveTemplate && !promptComposerActiveTemplate.isBuiltin" class="prompt-compose-actions">
|
|
83
88
|
<button
|
|
84
89
|
type="button"
|
|
85
90
|
class="btn-mini"
|
|
@@ -88,6 +93,31 @@
|
|
|
88
93
|
</div>
|
|
89
94
|
</div>
|
|
90
95
|
|
|
96
|
+
<div v-if="promptComposerActiveTemplate && promptComposerActiveTemplate.vars && promptComposerActiveTemplate.vars.length" class="prompt-vars-block">
|
|
97
|
+
<div class="prompt-vars-head">
|
|
98
|
+
<div>
|
|
99
|
+
<div class="prompt-vars-title">{{ t('plugins.promptTemplates.vars.title') }}</div>
|
|
100
|
+
<div v-if="!promptComposerActiveTemplate.isBuiltin" class="plugins-panel-note">{{ t('plugins.promptTemplates.compose.varsHint') }}</div>
|
|
101
|
+
<div v-if="promptComposerMissingVars.length" class="plugins-panel-note">未填 {{ promptComposerMissingVars.length }} 项</div>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="prompt-editor-actions">
|
|
104
|
+
<button v-if="promptComposerMissingVars.length" type="button" class="btn-mini" @click="focusPromptComposerFirstMissingVar" :disabled="pluginsLoading">跳到未填</button>
|
|
105
|
+
<button type="button" class="btn-mini" @click="resetPromptComposerVarValues" :disabled="pluginsLoading">{{ t('plugins.promptTemplates.vars.reset') }}</button>
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="prompt-vars-grid">
|
|
109
|
+
<label v-for="(name, idx) in promptComposerActiveTemplate.vars" :key="'prompt-compose-var-' + name" class="prompt-var-row">
|
|
110
|
+
<span class="prompt-var-label mono">{{ name }}</span>
|
|
111
|
+
<template v-if="idx === 0">
|
|
112
|
+
<input ref="promptComposerFirstField" :class="['form-input', 'prompt-var-input', { 'is-missing': promptComposerMissingVars.includes(name) }]" type="text" :value="promptComposerVarValues[name] || ''" @input="setPromptComposerVarValue(name, $event.target.value)" :placeholder="t('plugins.promptTemplates.vars.valuePlaceholder', { name })">
|
|
113
|
+
</template>
|
|
114
|
+
<template v-else>
|
|
115
|
+
<input :class="['form-input', 'prompt-var-input', { 'is-missing': promptComposerMissingVars.includes(name) }]" type="text" :value="promptComposerVarValues[name] || ''" @input="setPromptComposerVarValue(name, $event.target.value)" :placeholder="t('plugins.promptTemplates.vars.valuePlaceholder', { name })">
|
|
116
|
+
</template>
|
|
117
|
+
</label>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
91
121
|
<div class="prompt-preview-block prompt-compose-preview">
|
|
92
122
|
<div class="prompt-vars-head">
|
|
93
123
|
<div>
|
|
@@ -183,7 +213,7 @@
|
|
|
183
213
|
<div v-else class="prompt-vars-grid">
|
|
184
214
|
<label v-for="name in promptTemplateVars" :key="'prompt-var-' + name" class="prompt-var-row">
|
|
185
215
|
<span class="prompt-var-label mono">{{ name }}</span>
|
|
186
|
-
<input class="form-input prompt-var-input" type="text" :
|
|
216
|
+
<input class="form-input prompt-var-input" type="text" :readonly="promptTemplateDraft.isBuiltin" :value="promptTemplateVarValues[name] || ''" @input="setPromptVariableValue(name, $event.target.value)" :placeholder="t('plugins.promptTemplates.vars.valuePlaceholder', { name })">
|
|
187
217
|
</label>
|
|
188
218
|
</div>
|
|
189
219
|
</div>
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
<input
|
|
52
52
|
class="session-query-input"
|
|
53
53
|
v-model="sessionQuery"
|
|
54
|
-
@keyup.enter="
|
|
54
|
+
@keyup.enter="onSessionFilterChange"
|
|
55
55
|
:disabled="sessionsLoading || !isSessionQueryEnabled"
|
|
56
56
|
:placeholder="sessionQueryPlaceholder">
|
|
57
57
|
</div>
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
class="session-role-select"
|
|
61
61
|
v-model="sessionRoleFilter"
|
|
62
62
|
@change="onSessionFilterChange"
|
|
63
|
-
disabled>
|
|
63
|
+
:disabled="sessionsLoading">
|
|
64
64
|
<option value="all">{{ t('sessions.role.all') }}</option>
|
|
65
65
|
<option value="user">{{ t('sessions.role.user') }}</option>
|
|
66
66
|
<option value="assistant">{{ t('sessions.role.assistant') }}</option>
|
|
@@ -70,12 +70,18 @@
|
|
|
70
70
|
class="session-time-select"
|
|
71
71
|
v-model="sessionTimePreset"
|
|
72
72
|
@change="onSessionFilterChange"
|
|
73
|
-
disabled>
|
|
73
|
+
:disabled="sessionsLoading">
|
|
74
74
|
<option value="all">{{ t('sessions.time.all') }}</option>
|
|
75
75
|
<option value="7d">{{ t('sessions.time.7d') }}</option>
|
|
76
76
|
<option value="30d">{{ t('sessions.time.30d') }}</option>
|
|
77
77
|
<option value="90d">{{ t('sessions.time.90d') }}</option>
|
|
78
78
|
</select>
|
|
79
|
+
<button class="btn-tool btn-tool-compact" type="button" @click="copySessionsFilterShareUrl" :disabled="sessionsLoading">
|
|
80
|
+
复制筛选链接
|
|
81
|
+
</button>
|
|
82
|
+
<button class="btn-tool btn-tool-compact" type="button" @click="clearSessionFilters" :disabled="sessionsLoading">
|
|
83
|
+
{{ t('common.resetFilters') }}
|
|
84
|
+
</button>
|
|
79
85
|
</div>
|
|
80
86
|
</div>
|
|
81
87
|
<div class="session-toolbar-footer">
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
<span class="selector-title">{{ t('usage.overview') }}</span>
|
|
11
11
|
</div>
|
|
12
12
|
<div class="usage-range-group" role="group" :aria-label="t('usage.range.aria')">
|
|
13
|
-
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '7d' }" @click="
|
|
14
|
-
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '30d' }" @click="
|
|
15
|
-
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === 'all' }" @click="
|
|
16
|
-
<button type="button" class="usage-range-btn" @click="loadSessionsUsage({ forceRefresh: true })" :disabled="sessionsUsageLoading">{{ sessionsUsageLoading ? t('usage.refreshing') : t('usage.refresh') }}</button>
|
|
13
|
+
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '7d' }" @click="setSessionsUsageTimeRange('7d')">{{ t('usage.range.7d') }}</button>
|
|
14
|
+
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === '30d' }" @click="setSessionsUsageTimeRange('30d')">{{ t('usage.range.30d') }}</button>
|
|
15
|
+
<button type="button" class="usage-range-btn" :class="{ active: sessionsUsageTimeRange === 'all' }" @click="setSessionsUsageTimeRange('all')">{{ t('usage.range.all') }}</button>
|
|
16
|
+
<button type="button" class="usage-range-btn" @click="loadSessionsUsage({ forceRefresh: true, range: sessionsUsageTimeRange })" :disabled="sessionsUsageLoading">{{ sessionsUsageLoading ? t('usage.refreshing') : t('usage.refresh') }}</button>
|
|
17
17
|
</div>
|
|
18
18
|
</div>
|
|
19
19
|
|
|
@@ -302,7 +302,7 @@
|
|
|
302
302
|
<section class="usage-card">
|
|
303
303
|
<div class="usage-card-title">{{ t('usage.paths.title') }}</div>
|
|
304
304
|
<div v-if="!sessionUsageCharts.topPaths.length" class="usage-list-value">{{ t('usage.paths.empty') }}</div>
|
|
305
|
-
<div v-else class="usage-list">
|
|
305
|
+
<div v-else class="usage-list usage-list-scroll usage-list-top-paths">
|
|
306
306
|
<div v-for="item in sessionUsageCharts.topPaths" :key="item.path" class="usage-list-row">
|
|
307
307
|
<div class="usage-list-label">{{ t('usage.paths.count', { count: item.count }) }}</div>
|
|
308
308
|
<div class="usage-progress"><div class="usage-progress-fill" :style="{ width: ((item.count / Math.max((sessionUsageCharts.topPaths.length ? sessionUsageCharts.topPaths[0].count : 1), 1)) * 100) + '%' }"></div></div>
|