codexmate 0.0.22 → 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.
Files changed (66) hide show
  1. package/README.md +5 -3
  2. package/README.zh.md +8 -5
  3. package/cli/auth-profiles.js +23 -7
  4. package/cli/doctor-core.js +903 -0
  5. package/cli/import-skills-url.js +334 -0
  6. package/cli.js +304 -208
  7. package/lib/cli-models-utils.js +0 -40
  8. package/lib/cli-network-utils.js +28 -2
  9. package/package.json +5 -2
  10. package/plugins/README.md +20 -0
  11. package/plugins/README.zh-CN.md +20 -0
  12. package/plugins/prompt-templates/comment-polish/index.mjs +25 -0
  13. package/plugins/prompt-templates/computed.mjs +253 -0
  14. package/plugins/prompt-templates/index.mjs +8 -0
  15. package/plugins/prompt-templates/manifest.mjs +15 -0
  16. package/plugins/prompt-templates/methods.mjs +619 -0
  17. package/plugins/prompt-templates/overview.mjs +90 -0
  18. package/plugins/prompt-templates/ownership.mjs +19 -0
  19. package/plugins/prompt-templates/rule-ack/index.mjs +21 -0
  20. package/plugins/prompt-templates/storage.mjs +64 -0
  21. package/plugins/registry.mjs +16 -0
  22. package/res/logo-pack.webp +0 -0
  23. package/web-ui/app.js +68 -34
  24. package/web-ui/index.html +4 -3
  25. package/web-ui/modules/app.computed.dashboard.mjs +22 -22
  26. package/web-ui/modules/app.computed.main-tabs.mjs +9 -2
  27. package/web-ui/modules/app.methods.agents.mjs +91 -3
  28. package/web-ui/modules/app.methods.codex-config.mjs +153 -164
  29. package/web-ui/modules/app.methods.install.mjs +16 -0
  30. package/web-ui/modules/app.methods.navigation.mjs +76 -0
  31. package/web-ui/modules/app.methods.runtime.mjs +24 -2
  32. package/web-ui/modules/app.methods.session-browser.mjs +73 -1
  33. package/web-ui/modules/app.methods.startup-claude.mjs +12 -0
  34. package/web-ui/modules/app.methods.task-orchestration.mjs +96 -11
  35. package/web-ui/modules/config-mode.computed.mjs +1 -3
  36. package/web-ui/modules/i18n.dict.mjs +2039 -0
  37. package/web-ui/modules/i18n.mjs +2 -1555
  38. package/web-ui/modules/plugins.computed.mjs +2 -219
  39. package/web-ui/modules/plugins.methods.mjs +2 -619
  40. package/web-ui/modules/plugins.storage.mjs +11 -37
  41. package/web-ui/modules/sessions-filters-url.mjs +85 -0
  42. package/web-ui/partials/index/layout-header.html +38 -34
  43. package/web-ui/partials/index/modal-config-template-agents.html +3 -4
  44. package/web-ui/partials/index/modal-health-check.html +33 -60
  45. package/web-ui/partials/index/panel-config-claude.html +56 -15
  46. package/web-ui/partials/index/panel-config-codex.html +68 -19
  47. package/web-ui/partials/index/panel-config-openclaw.html +8 -3
  48. package/web-ui/partials/index/panel-dashboard.html +186 -0
  49. package/web-ui/partials/index/panel-docs.html +1 -1
  50. package/web-ui/partials/index/panel-market.html +3 -0
  51. package/web-ui/partials/index/panel-orchestration.html +105 -111
  52. package/web-ui/partials/index/panel-plugins.html +48 -12
  53. package/web-ui/partials/index/panel-sessions.html +12 -3
  54. package/web-ui/partials/index/panel-settings.html +1 -1
  55. package/web-ui/partials/index/panel-usage.html +7 -6
  56. package/web-ui/styles/controls-forms.css +16 -2
  57. package/web-ui/styles/dashboard.css +274 -0
  58. package/web-ui/styles/layout-shell.css +11 -5
  59. package/web-ui/styles/navigation-panels.css +8 -0
  60. package/web-ui/styles/plugins-panel.css +5 -0
  61. package/web-ui/styles/sessions-list.css +3 -3
  62. package/web-ui/styles/sessions-usage.css +37 -0
  63. package/web-ui/styles/skills-market.css +12 -2
  64. package/web-ui/styles/task-orchestration.css +57 -11
  65. package/web-ui/styles.css +1 -0
  66. package/res/logo.png +0 -0
@@ -8,23 +8,26 @@
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">Task orchestration</div>
12
- <div class="selector-title">把需求拆成可执行步骤</div>
13
- <div class="skills-panel-note task-hero-copy">先写目标,再预览,再执行。</div>
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
+ </button>
22
+ <button type="button" class="btn-tool btn-tool-compact" @click="switchMainTab('dashboard')" :disabled="loading || !!initError">
23
+ {{ t('dashboard.doctor.title') }}
21
24
  </button>
22
25
  </div>
23
26
  </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">运行中 <strong>{{ taskOrchestrationQueueStats.running }}</strong></div>
26
- <div class="task-hero-meta">排队中 <strong>{{ taskOrchestrationQueueStats.queued }}</strong></div>
27
- <div class="task-hero-meta">运行记录 <strong>{{ taskOrchestration.runs.length }}</strong></div>
27
+ <div v-if="taskOrchestrationQueueStats.running || taskOrchestrationQueueStats.queued || taskOrchestration.runs.length" class="task-hero-meta-strip" :aria-label="t('orchestration.summary.aria')">
28
+ <div class="task-hero-meta">{{ t('orchestration.summary.running') }} <strong>{{ taskOrchestrationQueueStats.running }}</strong></div>
29
+ <div class="task-hero-meta">{{ t('orchestration.summary.queued') }} <strong>{{ taskOrchestrationQueueStats.queued }}</strong></div>
30
+ <div class="task-hero-meta">{{ t('orchestration.summary.runs') }} <strong>{{ taskOrchestration.runs.length }}</strong></div>
28
31
  </div>
29
32
  </section>
30
33
 
@@ -34,27 +37,27 @@
34
37
  <div class="task-flow-head">
35
38
  <div class="task-flow-step">1</div>
36
39
  <div>
37
- <div class="task-flow-title">先把结果写清楚</div>
38
- <div class="task-flow-copy">只写会影响执行的内容。</div>
40
+ <div class="task-flow-title">{{ t('orchestration.step1.title') }}</div>
41
+ <div class="task-flow-copy">{{ t('orchestration.step1.subtitle') }}</div>
39
42
  </div>
40
43
  </div>
41
44
 
42
45
  <details v-if="!taskOrchestration.target.trim()" class="task-template-panel">
43
- <summary class="task-advanced-summary">快捷示例</summary>
46
+ <summary class="task-advanced-summary">{{ t('orchestration.templates.title') }}</summary>
44
47
  <div class="task-template-block">
45
48
  <div class="task-template-chip-group">
46
- <button type="button" class="task-template-chip" @click="taskOrchestration.target = '修复当前 PR review 评论,并补对应回归测试'; taskOrchestration.selectedEngine = 'codex'; taskOrchestration.workflowIdsText = ''; taskOrchestration.notes = '不要改动无关模块;需要给出验证结果'; taskOrchestration.followUpsText = '继续处理新增 review 评论\n最后更新 PR 摘要'">修 review + 回归</button>
47
- <button type="button" class="task-template-chip" @click="taskOrchestration.target = '先排查问题根因并给出执行计划,不直接修改代码'; taskOrchestration.selectedEngine = 'codex'; taskOrchestration.workflowIdsText = ''; taskOrchestration.notes = '优先定位根因、影响范围和风险点'; taskOrchestration.followUpsText = ''">只做排查规划</button>
48
- <button type="button" class="task-template-chip" @click="taskOrchestration.target = '用 Workflow 跑一组固定检查并整理结果'; taskOrchestration.selectedEngine = 'workflow'; taskOrchestration.workflowIdsText = 'diagnose-config\nsafe-provider-switch'; taskOrchestration.notes = '输出统一结论,避免重复描述'; taskOrchestration.followUpsText = ''">Workflow 批处理</button>
49
+ <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>
50
+ <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>
51
+ <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
52
  </div>
50
53
  </div>
51
54
  </details>
52
55
 
53
56
  <div class="selector-grid task-composer-grid task-composer-grid-primary">
54
57
  <label class="selector-field task-field task-field-wide task-goal-field">
55
- <span class="selector-label">目标</span>
56
- <textarea v-model="taskOrchestration.target" class="task-textarea task-textarea-goal" rows="5" placeholder="例如:修复当前 PR review 评论,并补对应回归测试;不要改无关模块"></textarea>
57
- <span class="task-field-hint">一句话写清结果、边界和验收标准就够了。</span>
58
+ <span class="selector-label">{{ t('orchestration.fields.target') }}</span>
59
+ <textarea v-model="taskOrchestration.target" class="task-textarea task-textarea-goal" rows="5" :placeholder="t('orchestration.fields.target.placeholder')"></textarea>
60
+ <span class="task-field-hint">{{ t('orchestration.fields.target.hint') }}</span>
58
61
  </label>
59
62
  </div>
60
63
 
@@ -64,12 +67,11 @@
64
67
  <div class="task-readiness-copy task-draft-inline-copy">{{ taskOrchestrationDraftReadiness.summary }}</div>
65
68
  </div>
66
69
  <div class="task-config-strip">
67
- <div class="task-config-pill">{{ taskOrchestration.selectedEngine === 'workflow' ? 'Workflow' : 'Codex' }}</div>
68
- <div class="task-config-pill">{{ taskOrchestration.allowWrite ? '允许写入' : '只读' }}</div>
69
- <div class="task-config-pill">{{ taskOrchestration.dryRun ? '仅预演' : '真实执行' }}</div>
70
- <div v-if="taskOrchestration.title.trim()" class="task-config-pill">标题已设</div>
71
- <div v-if="taskOrchestration.selectedEngine === 'workflow' && taskOrchestrationDraftMetrics.workflowCount > 0" class="task-config-pill">Workflow {{ taskOrchestrationDraftMetrics.workflowCount }}</div>
72
- <div v-if="taskOrchestration.plan" class="task-config-pill">计划 {{ taskOrchestrationDraftMetrics.planNodeCount }} 节点</div>
70
+ <div class="task-config-pill">{{ taskOrchestration.selectedEngine === 'workflow' ? t('orchestration.engine.workflow') : t('orchestration.engine.codex') }}</div>
71
+ <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>
72
+ <div v-if="taskOrchestration.title.trim()" class="task-config-pill">{{ t('orchestration.pills.hasTitle') }}</div>
73
+ <div v-if="taskOrchestration.selectedEngine === 'workflow' && taskOrchestrationDraftMetrics.workflowCount > 0" class="task-config-pill">{{ t('orchestration.pills.workflowCount', { count: taskOrchestrationDraftMetrics.workflowCount }) }}</div>
74
+ <div v-if="taskOrchestration.plan" class="task-config-pill">{{ t('orchestration.pills.planNodes', { count: taskOrchestrationDraftMetrics.planNodeCount }) }}</div>
73
75
  </div>
74
76
  </div>
75
77
  </div>
@@ -78,64 +80,59 @@
78
80
  <div class="task-flow-head">
79
81
  <div class="task-flow-step">2</div>
80
82
  <div>
81
- <div class="task-flow-title">选择执行方式</div>
82
- <div class="task-flow-copy">常用项默认展开,其余放高级设置。</div>
83
+ <div class="task-flow-title">{{ t('orchestration.step2.title') }}</div>
84
+ <div class="task-flow-copy">{{ t('orchestration.step2.subtitle') }}</div>
83
85
  </div>
84
86
  </div>
85
87
 
86
- <div class="selector-grid task-composer-grid task-composer-grid-compact">
88
+ <div class="selector-grid task-composer-grid task-composer-grid-compact task-composer-grid-inline">
87
89
  <label class="selector-field">
88
- <span class="selector-label">引擎</span>
89
- <select v-model="taskOrchestration.selectedEngine">
90
- <option value="codex">Codex</option>
91
- <option value="workflow">Workflow</option>
90
+ <span class="selector-label">{{ t('orchestration.fields.engine') }}</span>
91
+ <select v-model="taskOrchestration.selectedEngine" class="provider-fast-switch-select" disabled>
92
+ <option value="codex">{{ t('orchestration.engine.codex') }}</option>
93
+ <option value="workflow">{{ t('orchestration.engine.workflow') }}</option>
94
+ </select>
95
+ </label>
96
+ <label class="selector-field">
97
+ <span class="selector-label">{{ t('orchestration.fields.runMode') }}</span>
98
+ <select v-model="taskOrchestration.runMode" class="provider-fast-switch-select" disabled>
99
+ <option value="write">{{ t('orchestration.runMode.write') }}</option>
100
+ <option value="read">{{ t('orchestration.runMode.readOnly') }}</option>
101
+ <option value="dry-run">{{ t('orchestration.runMode.dryRun') }}</option>
92
102
  </select>
93
103
  </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
104
  </div>
108
105
 
109
106
  <details class="task-advanced-panel">
110
- <summary class="task-advanced-summary">高级设置</summary>
107
+ <summary class="task-advanced-summary">{{ t('orchestration.advanced.title') }}</summary>
111
108
  <div class="selector-grid task-composer-grid task-composer-grid-secondary">
112
109
  <label class="selector-field task-field-wide">
113
- <span class="selector-label">标题</span>
114
- <input v-model="taskOrchestration.title" type="text" placeholder="可选,默认从目标自动提取">
110
+ <span class="selector-label">{{ t('orchestration.fields.title') }}</span>
111
+ <input v-model="taskOrchestration.title" class="model-input" type="text" :placeholder="t('orchestration.fields.title.placeholder')">
115
112
  </label>
116
113
  <label class="selector-field task-field-wide">
117
- <span class="selector-label">说明</span>
118
- <textarea v-model="taskOrchestration.notes" class="task-textarea" rows="3" placeholder="例如:不要重写现有架构,只做增量实现"></textarea>
119
- <span class="task-field-hint">补边界、禁区、风格要求或验证要求。</span>
114
+ <span class="selector-label">{{ t('orchestration.fields.notes') }}</span>
115
+ <textarea v-model="taskOrchestration.notes" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.notes.placeholder')"></textarea>
116
+ <span class="task-field-hint">{{ t('orchestration.fields.notes.hint') }}</span>
120
117
  </label>
121
118
  <label class="selector-field task-field-wide">
122
- <span class="selector-label">后续动作(每行一条)</span>
123
- <textarea v-model="taskOrchestration.followUpsText" class="task-textarea" rows="3" placeholder="例如:\n继续处理 review 评论\n最后补回归测试"></textarea>
119
+ <span class="selector-label">{{ t('orchestration.fields.followUps') }}</span>
120
+ <textarea v-model="taskOrchestration.followUpsText" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.followUps.placeholder')"></textarea>
124
121
  </label>
125
122
  <label class="selector-field">
126
- <span class="selector-label">并发</span>
127
- <input v-model="taskOrchestration.concurrency" type="number" min="1" max="8">
128
- <span class="task-field-hint">复杂任务先从 1~2 开始更稳。</span>
123
+ <span class="selector-label">{{ t('orchestration.fields.concurrency') }}</span>
124
+ <input v-model="taskOrchestration.concurrency" class="model-input" type="number" min="1" max="8">
125
+ <span class="task-field-hint">{{ t('orchestration.fields.concurrency.hint') }}</span>
129
126
  </label>
130
127
  <label class="selector-field">
131
- <span class="selector-label">自动修复</span>
132
- <input v-model="taskOrchestration.autoFixRounds" type="number" min="0" max="5">
133
- <span class="task-field-hint">失败后自动再试几轮。</span>
128
+ <span class="selector-label">{{ t('orchestration.fields.autoFixRounds') }}</span>
129
+ <input v-model="taskOrchestration.autoFixRounds" class="model-input" type="number" min="0" max="5">
130
+ <span class="task-field-hint">{{ t('orchestration.fields.autoFixRounds.hint') }}</span>
134
131
  </label>
135
132
  <label v-if="taskOrchestration.selectedEngine === 'workflow'" class="selector-field task-field-wide">
136
- <span class="selector-label">Workflow ID(每行一条)</span>
137
- <textarea v-model="taskOrchestration.workflowIdsText" class="task-textarea" rows="3" placeholder="例如:\ndiagnose-config\nsafe-provider-switch"></textarea>
138
- <span class="task-field-hint">仅 Workflow 模式需要。当前本地可用 {{ taskOrchestration.workflows.length }} 个。</span>
133
+ <span class="selector-label">{{ t('orchestration.fields.workflowIds') }}</span>
134
+ <textarea v-model="taskOrchestration.workflowIdsText" class="task-textarea" rows="3" :placeholder="t('orchestration.fields.workflowIds.placeholder')"></textarea>
135
+ <span class="task-field-hint">{{ t('orchestration.fields.workflowIds.hint', { count: taskOrchestration.workflows.length }) }}</span>
139
136
  <div v-if="taskOrchestration.workflows.length" class="task-workflow-suggestions">
140
137
  <button
141
138
  v-for="workflow in taskOrchestration.workflows"
@@ -144,7 +141,7 @@
144
141
  class="task-workflow-chip"
145
142
  @click="appendTaskWorkflowId(workflow.id || workflow.name)">
146
143
  <span>{{ workflow.name || workflow.id }}</span>
147
- <small v-if="workflow.stepCount">{{ workflow.stepCount }} 步</small>
144
+ <small v-if="workflow.stepCount">{{ t('orchestration.workflow.stepCount', { count: workflow.stepCount }) }}</small>
148
145
  </button>
149
146
  </div>
150
147
  </label>
@@ -156,27 +153,24 @@
156
153
  <div class="task-flow-head">
157
154
  <div class="task-flow-step">3</div>
158
155
  <div>
159
- <div class="task-flow-title">先预览,再执行</div>
160
- <div class="task-flow-copy">先确认计划,再决定立即执行还是入队。</div>
156
+ <div class="task-flow-title">{{ t('orchestration.step3.title') }}</div>
157
+ <div class="task-flow-copy">{{ t('orchestration.step3.subtitle') }}</div>
161
158
  </div>
162
159
  </div>
163
160
  <div class="task-action-row task-action-row-prominent">
164
161
  <button type="button" class="btn-tool task-action-preview" @click="previewTaskPlan()" :disabled="taskOrchestration.planning || taskOrchestration.running || !taskOrchestration.target.trim()">
165
- {{ taskOrchestration.planning ? '规划中...' : '预览计划' }}
162
+ {{ taskOrchestration.planning ? t('orchestration.actions.planning') : t('orchestration.actions.previewOnly') }}
166
163
  </button>
167
164
  <div class="task-action-row-right task-action-row-right-prominent">
168
- <button type="button" class="btn-tool btn-primary" @click="runTaskOrchestration()" :disabled="taskOrchestration.running || !taskOrchestration.target.trim()">
169
- {{ taskOrchestration.running ? '启动中...' : '立即执行' }}
170
- </button>
171
- <button type="button" class="btn-tool" @click="addTaskOrchestrationToQueue()" :disabled="taskOrchestration.queueAdding || !taskOrchestration.target.trim()">
172
- {{ taskOrchestration.queueAdding ? '加入中...' : '加入队列' }}
165
+ <button type="button" class="btn-tool btn-primary" @click="planAndRunTaskOrchestration()" :disabled="taskOrchestration.running || taskOrchestration.planning || !taskOrchestration.target.trim()">
166
+ {{ (taskOrchestration.running || taskOrchestration.planning) ? t('orchestration.actions.preparing') : (taskOrchestration.runMode === 'dry-run' ? t('orchestration.actions.generatePlan') : t('orchestration.actions.planAndRun')) }}
173
167
  </button>
174
- <button v-if="taskOrchestration.queue.length" type="button" class="btn-tool" @click="startTaskQueueRunner()" :disabled="taskOrchestration.queueStarting">
175
- {{ taskOrchestration.queueStarting ? '启动中...' : '开始队列' }}
168
+ <button type="button" class="btn-tool" @click="queueTaskOrchestrationAndStart()" :disabled="taskOrchestration.queueAdding || taskOrchestration.queueStarting || taskOrchestration.planning || !taskOrchestration.target.trim()">
169
+ {{ (taskOrchestration.queueAdding || taskOrchestration.queueStarting) ? t('orchestration.actions.processing') : t('orchestration.actions.queueAndStart') }}
176
170
  </button>
177
171
  </div>
178
172
  </div>
179
- <div class="task-action-caption">预览不会执行。批量任务再入队。</div>
173
+ <div class="task-action-caption">{{ t('orchestration.actions.caption') }}</div>
180
174
  </div>
181
175
  </section>
182
176
  </div>
@@ -186,13 +180,13 @@
186
180
  class="selector-section task-stage-card">
187
181
  <div class="task-stage-empty">
188
182
  <div>
189
- <div class="selector-title">有内容时再展开工作区</div>
190
- <div class="skills-panel-note">先写目标,再预览计划。</div>
183
+ <div class="selector-title">{{ t('orchestration.stage.title') }}</div>
184
+ <div class="skills-panel-note">{{ t('orchestration.stage.subtitle') }}</div>
191
185
  </div>
192
186
  <div class="task-stage-strip">
193
- <div class="task-stage-pill">写目标</div>
194
- <div class="task-stage-pill">预览</div>
195
- <div class="task-stage-pill">执行或入队</div>
187
+ <div class="task-stage-pill">{{ t('orchestration.stage.pill.target') }}</div>
188
+ <div class="task-stage-pill">{{ t('orchestration.stage.pill.preview') }}</div>
189
+ <div class="task-stage-pill">{{ t('orchestration.stage.pill.run') }}</div>
196
190
  </div>
197
191
  </div>
198
192
  </section>
@@ -206,8 +200,8 @@
206
200
  <div v-if="taskOrchestration.lastError" class="task-issue-item">{{ taskOrchestration.lastError }}</div>
207
201
  <div class="selector-header task-section-header">
208
202
  <div>
209
- <span class="selector-title">计划预览</span>
210
- <div class="skills-panel-note">先确认节点、波次和依赖。</div>
203
+ <span class="selector-title">{{ t('orchestration.plan.title') }}</span>
204
+ <div class="skills-panel-note">{{ t('orchestration.plan.subtitle') }}</div>
211
205
  </div>
212
206
  </div>
213
207
  <div v-if="taskOrchestration.planIssues.length" class="task-issues-list">
@@ -223,15 +217,15 @@
223
217
  <template v-if="taskOrchestration.plan">
224
218
  <div class="task-plan-summary-strip">
225
219
  <div class="task-plan-summary-item">
226
- <span class="task-plan-summary-label">节点数</span>
220
+ <span class="task-plan-summary-label">{{ t('orchestration.plan.summary.nodes') }}</span>
227
221
  <strong>{{ taskOrchestration.plan.nodes.length }}</strong>
228
222
  </div>
229
223
  <div class="task-plan-summary-item">
230
- <span class="task-plan-summary-label">波次</span>
224
+ <span class="task-plan-summary-label">{{ t('orchestration.plan.summary.waves') }}</span>
231
225
  <strong>{{ taskOrchestration.plan.waves.length }}</strong>
232
226
  </div>
233
227
  <div class="task-plan-summary-item">
234
- <span class="task-plan-summary-label">引擎</span>
228
+ <span class="task-plan-summary-label">{{ t('orchestration.plan.summary.engine') }}</span>
235
229
  <strong>{{ taskOrchestration.plan.engine }}</strong>
236
230
  </div>
237
231
  </div>
@@ -248,9 +242,9 @@
248
242
  <div class="task-node-title">{{ node.title || node.id }}</div>
249
243
  <div class="task-node-meta">{{ node.id }} · {{ node.kind }}<span v-if="node.workflowId"> · {{ node.workflowId }}</span></div>
250
244
  </div>
251
- <span :class="['pill', node.write ? 'configured' : 'empty']">{{ node.write ? 'write' : 'read-only' }}</span>
245
+ <span :class="['pill', node.write ? 'configured' : 'empty']">{{ node.write ? t('orchestration.plan.node.write') : t('orchestration.plan.node.readOnly') }}</span>
252
246
  </div>
253
- <div class="task-node-deps">依赖:{{ formatTaskNodeDependencies(node) }}</div>
247
+ <div class="task-node-deps">{{ t('orchestration.labels.dependencies') }}{{ formatTaskNodeDependencies(node) }}</div>
254
248
  </div>
255
249
  </div>
256
250
  </template>
@@ -261,15 +255,15 @@
261
255
  class="selector-section task-workbench-card">
262
256
  <div class="selector-header task-section-header">
263
257
  <div>
264
- <span class="selector-title">执行工作台</span>
265
- <div class="skills-panel-note">有内容时才展开。</div>
258
+ <span class="selector-title">{{ t('orchestration.workbench.title') }}</span>
259
+ <div class="skills-panel-note">{{ t('orchestration.workbench.subtitle') }}</div>
266
260
  </div>
267
261
  <div class="settings-tab-actions task-header-actions">
268
262
  <button type="button" class="btn-tool btn-tool-compact" @click="loadTaskOrchestrationOverview({ forceRefresh: true, includeDetail: true })" :disabled="taskOrchestration.loading">
269
- {{ taskOrchestration.loading ? '刷新中...' : '刷新' }}
263
+ {{ taskOrchestration.loading ? t('common.refreshing') : t('common.refresh') }}
270
264
  </button>
271
265
  <button v-if="taskOrchestration.queue.length" type="button" class="btn-tool btn-tool-compact" @click="startTaskQueueRunner()" :disabled="taskOrchestration.queueStarting">
272
- {{ taskOrchestration.queueStarting ? '启动中...' : '开始队列' }}
266
+ {{ taskOrchestration.queueStarting ? t('orchestration.queue.starting') : t('orchestration.queue.start') }}
273
267
  </button>
274
268
  </div>
275
269
  </div>
@@ -278,16 +272,16 @@
278
272
  v-if="(taskOrchestration.queue.length ? 1 : 0) + (taskOrchestration.runs.length ? 1 : 0) + ((taskOrchestration.selectedRunId || taskOrchestration.selectedRunError) ? 1 : 0) > 1"
279
273
  class="task-workbench-tabs"
280
274
  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'">队列 {{ taskOrchestration.queue.length }}</button>
283
- <button v-if="taskOrchestration.runs.length" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'runs' }" @click="taskOrchestration.workspaceTab = 'runs'">运行记录 {{ taskOrchestration.runs.length }}</button>
284
- <button v-if="taskOrchestration.selectedRunId || taskOrchestration.selectedRunError" type="button" class="task-workbench-tab" :class="{ active: taskOrchestration.workspaceTab === 'detail' }" @click="taskOrchestration.workspaceTab = 'detail'">运行详情</button>
275
+ :aria-label="t('orchestration.workbench.tabs.aria')">
276
+ <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>
277
+ <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>
278
+ <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
279
  </div>
286
280
 
287
281
  <div v-if="taskOrchestration.workspaceTab === 'queue' || (!taskOrchestration.runs.length && !taskOrchestration.selectedRunId && !taskOrchestration.selectedRunError)" class="task-workbench-panel">
288
282
  <div v-if="!taskOrchestration.queue.length" class="task-empty-state">
289
- <div class="task-empty-title">当前没有排队任务</div>
290
- <div class="task-empty-copy">批量任务可先入队,再启动队列。</div>
283
+ <div class="task-empty-title">{{ t('orchestration.queue.empty.title') }}</div>
284
+ <div class="task-empty-copy">{{ t('orchestration.queue.empty.subtitle') }}</div>
291
285
  </div>
292
286
  <div v-else class="task-runtime-list">
293
287
  <div
@@ -307,7 +301,7 @@
307
301
  </div>
308
302
  <div class="task-runtime-item-actions">
309
303
  <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'">取消</button>
304
+ <button type="button" class="btn-mini" @click.stop="cancelTaskRunFromUi(item.taskId)" :disabled="item.status !== 'queued' && item.status !== 'running'">{{ t('common.cancel') }}</button>
311
305
  </div>
312
306
  </div>
313
307
  </div>
@@ -315,8 +309,8 @@
315
309
 
316
310
  <div v-else-if="taskOrchestration.workspaceTab === 'runs' || (!taskOrchestration.queue.length && taskOrchestration.runs.length && !taskOrchestration.selectedRunId && !taskOrchestration.selectedRunError)" class="task-workbench-panel">
317
311
  <div v-if="!taskOrchestration.runs.length" class="task-empty-state">
318
- <div class="task-empty-title">还没有运行记录</div>
319
- <div class="task-empty-copy">执行后会显示最近运行记录。</div>
312
+ <div class="task-empty-title">{{ t('orchestration.runs.empty.title') }}</div>
313
+ <div class="task-empty-copy">{{ t('orchestration.runs.empty.subtitle') }}</div>
320
314
  </div>
321
315
  <div v-else class="task-runtime-list">
322
316
  <button
@@ -340,38 +334,38 @@
340
334
  <div v-else class="task-workbench-panel">
341
335
  <div class="task-detail-toolbar settings-tab-actions">
342
336
  <button type="button" class="btn-tool btn-tool-compact" @click="taskOrchestration.selectedRunId ? loadTaskRunDetail(taskOrchestration.selectedRunId) : null" :disabled="!taskOrchestration.selectedRunId || taskOrchestration.selectedRunLoading">
343
- {{ taskOrchestration.selectedRunLoading ? '刷新中...' : '刷新详情' }}
337
+ {{ taskOrchestration.selectedRunLoading ? t('common.refreshing') : t('orchestration.detail.refresh') }}
344
338
  </button>
345
339
  <button type="button" class="btn-tool btn-tool-compact" @click="retryTaskRunFromUi(taskOrchestration.selectedRunId)" :disabled="!taskOrchestration.selectedRunId || taskOrchestration.retrying">
346
- {{ taskOrchestration.retrying ? '重试中...' : '重试' }}
340
+ {{ taskOrchestration.retrying ? t('orchestration.detail.retrying') : t('orchestration.detail.retry') }}
347
341
  </button>
348
342
  <button type="button" class="btn-tool btn-tool-compact" @click="cancelTaskRunFromUi(taskOrchestration.selectedRunId)" :disabled="!taskOrchestrationSelectedRun || !taskOrchestrationSelectedRun.run || !isTaskRunActive(taskOrchestrationSelectedRun.run.status)">
349
- 取消
343
+ {{ t('common.cancel') }}
350
344
  </button>
351
345
  </div>
352
346
 
353
347
  <div v-if="taskOrchestration.selectedRunError" class="task-issue-item">{{ taskOrchestration.selectedRunError }}</div>
354
348
  <div v-if="!taskOrchestrationSelectedRun" class="task-empty-state">
355
- <div class="task-empty-title">选择一条运行记录查看详情</div>
356
- <div class="task-empty-copy">这里会显示节点状态、摘要和日志。</div>
349
+ <div class="task-empty-title">{{ t('orchestration.detail.empty.title') }}</div>
350
+ <div class="task-empty-copy">{{ t('orchestration.detail.empty.subtitle') }}</div>
357
351
  </div>
358
352
  <template v-else>
359
353
  <div class="task-detail-summary-strip">
360
354
  <div class="task-plan-summary-item">
361
- <span class="task-plan-summary-label">状态</span>
355
+ <span class="task-plan-summary-label">{{ t('orchestration.detail.summary.status') }}</span>
362
356
  <strong>{{ taskOrchestrationSelectedRun.run.status }}</strong>
363
357
  </div>
364
358
  <div class="task-plan-summary-item">
365
- <span class="task-plan-summary-label">耗时</span>
359
+ <span class="task-plan-summary-label">{{ t('orchestration.detail.summary.duration') }}</span>
366
360
  <strong>{{ taskOrchestrationSelectedRun.run.durationMs || 0 }}ms</strong>
367
361
  </div>
368
362
  <div class="task-plan-summary-item">
369
- <span class="task-plan-summary-label">节点数</span>
363
+ <span class="task-plan-summary-label">{{ t('orchestration.detail.summary.nodes') }}</span>
370
364
  <strong>{{ taskOrchestrationSelectedRunNodes.length }}</strong>
371
365
  </div>
372
366
  <div class="task-plan-summary-item">
373
- <span class="task-plan-summary-label">摘要</span>
374
- <strong>{{ taskOrchestrationSelectedRun.run.summary || '暂无' }}</strong>
367
+ <span class="task-plan-summary-label">{{ t('orchestration.detail.summary.summary') }}</span>
368
+ <strong>{{ taskOrchestrationSelectedRun.run.summary || t('common.none') }}</strong>
375
369
  </div>
376
370
  </div>
377
371
  <div v-if="taskOrchestrationSelectedRun.run.error" class="task-issue-item">{{ taskOrchestrationSelectedRun.run.error }}</div>
@@ -380,13 +374,13 @@
380
374
  <div class="task-node-head">
381
375
  <div>
382
376
  <div class="task-node-title">{{ node.title || node.id }}</div>
383
- <div class="task-node-meta">{{ node.id }} · attempts {{ node.attemptCount || 0 }} · auto-fix {{ node.autoFixRounds || 0 }}</div>
377
+ <div class="task-node-meta">{{ t('orchestration.detail.node.meta', { id: node.id, attempts: (node.attemptCount || 0), autoFix: (node.autoFixRounds || 0) }) }}</div>
384
378
  </div>
385
379
  <span :class="['pill', taskRunStatusTone(node.status)]">{{ node.status }}</span>
386
380
  </div>
387
381
  <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">错误:{{ node.error }}</div>
389
- <div class="task-node-deps">依赖:{{ formatTaskNodeDependencies(node) }}</div>
382
+ <div v-if="node.error && node.error !== node.summary" class="task-node-deps">{{ t('orchestration.labels.error') }}{{ node.error }}</div>
383
+ <div class="task-node-deps">{{ t('orchestration.labels.dependencies') }}{{ formatTaskNodeDependencies(node) }}</div>
390
384
  <pre class="task-log-block">{{ formatTaskNodeLogs(node.logs) }}</pre>
391
385
  </div>
392
386
  </div>