codexmate 0.1.8 → 0.1.10
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/cli.js +63 -2696
- package/package.json +1 -1
- package/web-ui/app.js +27 -56
- package/web-ui/index.html +0 -1
- package/web-ui/modules/app.computed.dashboard.mjs +0 -3
- package/web-ui/modules/app.computed.main-tabs.mjs +0 -474
- package/web-ui/modules/app.methods.index.mjs +1 -3
- package/web-ui/modules/app.methods.navigation.mjs +1 -2
- package/web-ui/modules/app.methods.session-actions.mjs +146 -21
- package/web-ui/modules/app.methods.session-browser.mjs +5 -0
- package/web-ui/modules/app.methods.web-ui-preferences.mjs +20 -9
- package/web-ui/modules/i18n/locales/en.mjs +14 -265
- package/web-ui/modules/i18n/locales/ja.mjs +14 -265
- package/web-ui/modules/i18n/locales/vi.mjs +14 -266
- package/web-ui/modules/i18n/locales/zh-tw.mjs +14 -265
- package/web-ui/modules/i18n/locales/zh.mjs +14 -265
- package/web-ui/partials/index/layout-header.html +0 -48
- package/web-ui/partials/index/panel-dashboard.html +0 -21
- package/web-ui/partials/index/panel-sessions.html +30 -2
- package/web-ui/res/web-ui-render.precompiled.js +105 -1193
- package/web-ui/session-helpers.mjs +3 -16
- package/web-ui/styles/sessions-list.css +96 -0
- package/web-ui/styles.css +0 -1
- package/lib/automation.js +0 -404
- package/lib/task-orchestrator.js +0 -938
- package/lib/task-workspace-chat.js +0 -292
- package/web-ui/modules/app.methods.task-orchestration.mjs +0 -895
- package/web-ui/partials/index/panel-orchestration.html +0 -598
- package/web-ui/styles/task-orchestration.css +0 -2979
|
@@ -1,379 +1,3 @@
|
|
|
1
|
-
function normalizeTaskDraftLines(text) {
|
|
2
|
-
return String(text || '')
|
|
3
|
-
.split(/\r?\n/g)
|
|
4
|
-
.map((item) => item.trim())
|
|
5
|
-
.filter(Boolean);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
function readTaskOrchestrationDraftMetrics(taskOrchestration) {
|
|
9
|
-
const state = taskOrchestration && typeof taskOrchestration === 'object' ? taskOrchestration : {};
|
|
10
|
-
const target = String(state.target || '').trim();
|
|
11
|
-
const notes = String(state.notes || '').trim();
|
|
12
|
-
const title = String(state.title || '').trim();
|
|
13
|
-
const workflowIds = normalizeTaskDraftLines(state.workflowIdsText);
|
|
14
|
-
const followUps = normalizeTaskDraftLines(state.followUpsText);
|
|
15
|
-
const requestCount = target ? followUps.length + 1 : 0;
|
|
16
|
-
const engine = String(state.selectedEngine || 'openai-chat').trim().toLowerCase() === 'workflow' ? 'workflow' : 'openai-chat';
|
|
17
|
-
const runMode = String(state.runMode || 'write').trim().toLowerCase();
|
|
18
|
-
const allowWrite = runMode === 'write';
|
|
19
|
-
const dryRun = runMode === 'dry-run';
|
|
20
|
-
const plan = state.plan && typeof state.plan === 'object' ? state.plan : null;
|
|
21
|
-
const planNodes = Array.isArray(plan && plan.nodes) ? plan.nodes : [];
|
|
22
|
-
const planIssues = Array.isArray(state.planIssues) ? state.planIssues : [];
|
|
23
|
-
const planWarnings = Array.isArray(state.planWarnings) ? state.planWarnings : [];
|
|
24
|
-
return {
|
|
25
|
-
engine,
|
|
26
|
-
runMode,
|
|
27
|
-
title,
|
|
28
|
-
target,
|
|
29
|
-
notes,
|
|
30
|
-
workflowIds,
|
|
31
|
-
followUps,
|
|
32
|
-
hasTarget: target.length > 0,
|
|
33
|
-
hasNotes: notes.length > 0,
|
|
34
|
-
hasTitle: title.length > 0,
|
|
35
|
-
hasPlan: !!plan,
|
|
36
|
-
planNodes,
|
|
37
|
-
planIssues,
|
|
38
|
-
planWarnings,
|
|
39
|
-
workflowCount: workflowIds.length,
|
|
40
|
-
followUpCount: followUps.length,
|
|
41
|
-
requestCount,
|
|
42
|
-
hasSequentialFollowUps: followUps.length > 0,
|
|
43
|
-
planNodeCount: planNodes.length,
|
|
44
|
-
allowWrite,
|
|
45
|
-
dryRun
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
function formatTaskConversationMeta(items) {
|
|
51
|
-
return items.filter(Boolean).join(' · ');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function collectTaskRunWorkspaceFileLines(detail) {
|
|
55
|
-
const run = detail && detail.run && typeof detail.run === 'object' ? detail.run : null;
|
|
56
|
-
const nodes = Array.isArray(detail && detail.nodes)
|
|
57
|
-
? detail.nodes
|
|
58
|
-
: (Array.isArray(run && run.nodes) ? run.nodes : []);
|
|
59
|
-
const files = [];
|
|
60
|
-
for (const node of nodes) {
|
|
61
|
-
const output = node && node.output && typeof node.output === 'object' ? node.output : null;
|
|
62
|
-
const workspaceFiles = Array.isArray(output && output.workspaceFiles) ? output.workspaceFiles : [];
|
|
63
|
-
const materializedFiles = Array.isArray(output && output.materializedFiles) ? output.materializedFiles : [];
|
|
64
|
-
for (const file of workspaceFiles) {
|
|
65
|
-
if (!file || typeof file !== 'object') continue;
|
|
66
|
-
const op = String(file.operation || '').trim().toUpperCase() || 'FILE';
|
|
67
|
-
const filePath = String(file.relativePath || file.path || '').trim();
|
|
68
|
-
if (filePath) files.push(`${op} ${filePath}`);
|
|
69
|
-
}
|
|
70
|
-
for (const file of materializedFiles) {
|
|
71
|
-
if (!file || typeof file !== 'object') continue;
|
|
72
|
-
const filePath = String(file.relativePath || file.path || '').trim();
|
|
73
|
-
if (filePath) files.push(`WRITE ${filePath}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return Array.from(new Set(files)).slice(0, 6);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function normalizeTaskWorkspacePath(value) {
|
|
80
|
-
return String(value || '').trim().replace(/\\+/g, '/').replace(/\/$/, '');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function readTaskWorkspacePathFromItem(item) {
|
|
84
|
-
if (!item || typeof item !== 'object') return '';
|
|
85
|
-
return normalizeTaskWorkspacePath(item.cwd || item.workspacePath || item.projectPath || item.path);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function formatTaskWorkspaceLabel(workspacePath, fallback = 'Auto workspace') {
|
|
89
|
-
const normalized = normalizeTaskWorkspacePath(workspacePath);
|
|
90
|
-
if (!normalized) return fallback;
|
|
91
|
-
const parts = normalized.split('/').filter(Boolean);
|
|
92
|
-
return parts.length ? parts[parts.length - 1] : normalized;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function readTaskItemTimestamp(item) {
|
|
96
|
-
if (!item || typeof item !== 'object') return '';
|
|
97
|
-
return String(item.updatedAt || item.completedAt || item.startedAt || item.createdAt || item.enqueuedAt || '').trim();
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function addTaskWorkspaceCandidate(workspaces, workspacePath, source, timestamp = '') {
|
|
101
|
-
const normalized = normalizeTaskWorkspacePath(workspacePath);
|
|
102
|
-
if (!normalized) return;
|
|
103
|
-
const key = normalized.toLowerCase();
|
|
104
|
-
const current = workspaces.get(key) || {
|
|
105
|
-
key,
|
|
106
|
-
path: normalized,
|
|
107
|
-
label: formatTaskWorkspaceLabel(normalized),
|
|
108
|
-
meta: normalized,
|
|
109
|
-
queueCount: 0,
|
|
110
|
-
runCount: 0,
|
|
111
|
-
lastActivity: ''
|
|
112
|
-
};
|
|
113
|
-
if (source === 'queue') current.queueCount += 1;
|
|
114
|
-
if (source === 'run') current.runCount += 1;
|
|
115
|
-
if (timestamp && (!current.lastActivity || timestamp > current.lastActivity)) {
|
|
116
|
-
current.lastActivity = timestamp;
|
|
117
|
-
}
|
|
118
|
-
workspaces.set(key, current);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function taskItemMatchesWorkspace(item, workspacePath) {
|
|
122
|
-
const selectedWorkspacePath = normalizeTaskWorkspacePath(workspacePath);
|
|
123
|
-
if (!selectedWorkspacePath) return true;
|
|
124
|
-
return readTaskWorkspacePathFromItem(item) === selectedWorkspacePath;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function createTaskWorkspaceItems(taskOrchestration) {
|
|
128
|
-
const state = taskOrchestration && typeof taskOrchestration === 'object' ? taskOrchestration : {};
|
|
129
|
-
const workspaces = new Map();
|
|
130
|
-
addTaskWorkspaceCandidate(workspaces, state.workspacePath, 'draft');
|
|
131
|
-
const detail = state.selectedRunDetail && typeof state.selectedRunDetail === 'object' ? state.selectedRunDetail : null;
|
|
132
|
-
if (detail) addTaskWorkspaceCandidate(workspaces, detail.cwd, 'detail');
|
|
133
|
-
const queue = Array.isArray(state.queue) ? state.queue : [];
|
|
134
|
-
const runs = Array.isArray(state.runs) ? state.runs : [];
|
|
135
|
-
queue.forEach((item) => addTaskWorkspaceCandidate(workspaces, readTaskWorkspacePathFromItem(item), 'queue', readTaskItemTimestamp(item)));
|
|
136
|
-
runs.forEach((item) => addTaskWorkspaceCandidate(workspaces, readTaskWorkspacePathFromItem(item), 'run', readTaskItemTimestamp(item)));
|
|
137
|
-
const items = Array.from(workspaces.values()).sort((a, b) => {
|
|
138
|
-
const byActivity = String(b.lastActivity || '').localeCompare(String(a.lastActivity || ''));
|
|
139
|
-
if (byActivity !== 0) return byActivity;
|
|
140
|
-
return a.label.localeCompare(b.label);
|
|
141
|
-
});
|
|
142
|
-
if (items.length === 0) {
|
|
143
|
-
items.push({
|
|
144
|
-
key: '__auto__',
|
|
145
|
-
path: '',
|
|
146
|
-
label: 'Auto workspace',
|
|
147
|
-
meta: 'Server default cwd',
|
|
148
|
-
queueCount: queue.length,
|
|
149
|
-
runCount: runs.length,
|
|
150
|
-
lastActivity: ''
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
return items;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
function createTaskWorkspaceSessions(taskOrchestration, workspacePath) {
|
|
157
|
-
const state = taskOrchestration && typeof taskOrchestration === 'object' ? taskOrchestration : {};
|
|
158
|
-
const queue = Array.isArray(state.queue) ? state.queue : [];
|
|
159
|
-
const runs = Array.isArray(state.runs) ? state.runs : [];
|
|
160
|
-
const queueSessions = queue
|
|
161
|
-
.filter((item) => taskItemMatchesWorkspace(item, workspacePath))
|
|
162
|
-
.map((item) => ({
|
|
163
|
-
id: item.taskId || item.lastRunId || `queue-${readTaskItemTimestamp(item)}`,
|
|
164
|
-
type: 'queue',
|
|
165
|
-
status: item.status || item.runStatus || 'queued',
|
|
166
|
-
title: item.title || item.target || item.taskId || 'Queued task',
|
|
167
|
-
meta: item.threadId || item.cwd || item.taskId || '',
|
|
168
|
-
taskId: item.taskId || '',
|
|
169
|
-
runId: item.lastRunId || '',
|
|
170
|
-
threadId: item.threadId || '',
|
|
171
|
-
cwd: readTaskWorkspacePathFromItem(item),
|
|
172
|
-
timestamp: readTaskItemTimestamp(item),
|
|
173
|
-
active: true
|
|
174
|
-
}));
|
|
175
|
-
const runSessions = runs
|
|
176
|
-
.filter((item) => taskItemMatchesWorkspace(item, workspacePath))
|
|
177
|
-
.map((item) => ({
|
|
178
|
-
id: item.runId || item.taskId || `run-${readTaskItemTimestamp(item)}`,
|
|
179
|
-
type: 'run',
|
|
180
|
-
status: item.status || 'completed',
|
|
181
|
-
title: item.title || item.summary || item.taskId || item.runId || 'Run',
|
|
182
|
-
meta: item.threadId || item.cwd || `${item.durationMs || 0}ms`,
|
|
183
|
-
taskId: item.taskId || '',
|
|
184
|
-
runId: item.runId || '',
|
|
185
|
-
threadId: item.threadId || '',
|
|
186
|
-
cwd: readTaskWorkspacePathFromItem(item),
|
|
187
|
-
timestamp: readTaskItemTimestamp(item),
|
|
188
|
-
active: false
|
|
189
|
-
}));
|
|
190
|
-
return queueSessions.concat(runSessions).sort((a, b) => {
|
|
191
|
-
if (a.active !== b.active) return a.active ? -1 : 1;
|
|
192
|
-
return String(b.timestamp || '').localeCompare(String(a.timestamp || ''));
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function createTaskConversationMessages(taskOrchestration, t = null) {
|
|
197
|
-
const state = taskOrchestration && typeof taskOrchestration === 'object' ? taskOrchestration : {};
|
|
198
|
-
const messages = [];
|
|
199
|
-
const target = String(state.target || '').trim();
|
|
200
|
-
const followUps = normalizeTaskDraftLines(state.followUpsText);
|
|
201
|
-
const detail = state.selectedRunDetail && typeof state.selectedRunDetail === 'object' ? state.selectedRunDetail : null;
|
|
202
|
-
const detailRun = detail && detail.run && typeof detail.run === 'object' ? detail.run : null;
|
|
203
|
-
if (detail) {
|
|
204
|
-
const fileLines = collectTaskRunWorkspaceFileLines(detail);
|
|
205
|
-
const resultLines = [];
|
|
206
|
-
if (detailRun && detailRun.summary) {
|
|
207
|
-
resultLines.push(detailRun.summary);
|
|
208
|
-
} else {
|
|
209
|
-
resultLines.push(translateTaskText(t, 'orchestration.chat.assistant.contextFallback', '已选中一个历史任务,继续时会继承它的线程和工作区。'));
|
|
210
|
-
}
|
|
211
|
-
if (fileLines.length > 0) {
|
|
212
|
-
resultLines.push(translateTaskText(t, 'orchestration.chat.assistant.filesSummary', `文件操作:${fileLines.join(';')}`, { files: fileLines.join(';') }));
|
|
213
|
-
}
|
|
214
|
-
messages.push({
|
|
215
|
-
id: 'context-run',
|
|
216
|
-
role: 'assistant',
|
|
217
|
-
label: detailRun && detailRun.status === 'success'
|
|
218
|
-
? translateTaskText(t, 'orchestration.chat.assistant.resultLabel', '实现结果')
|
|
219
|
-
: translateTaskText(t, 'orchestration.chat.assistant.contextLabel', '上一轮上下文'),
|
|
220
|
-
text: resultLines.join('\n'),
|
|
221
|
-
meta: formatTaskConversationMeta([
|
|
222
|
-
detail.threadId ? translateTaskText(t, 'orchestration.chat.meta.thread', `线程 ${detail.threadId}`, { value: detail.threadId }) : '',
|
|
223
|
-
detail.cwd ? translateTaskText(t, 'orchestration.chat.meta.workspace', `工作区 ${detail.cwd}`, { value: detail.cwd }) : '',
|
|
224
|
-
detailRun && detailRun.status ? detailRun.status : ''
|
|
225
|
-
])
|
|
226
|
-
});
|
|
227
|
-
} else if (!target && followUps.length === 0) {
|
|
228
|
-
messages.push({
|
|
229
|
-
id: 'assistant-empty',
|
|
230
|
-
role: 'assistant',
|
|
231
|
-
label: translateTaskText(t, 'orchestration.chat.assistant.readyLabel', 'Codexmate'),
|
|
232
|
-
text: translateTaskText(t, 'orchestration.chat.assistant.empty', '先发第一个需求;如果还有第二个需求,继续发送,Codexmate 会按顺序处理并保留上下文。'),
|
|
233
|
-
meta: translateTaskText(t, 'orchestration.chat.meta.order', '顺序执行 · 保留上下文')
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
if (target) {
|
|
237
|
-
messages.push({
|
|
238
|
-
id: 'user-target',
|
|
239
|
-
role: 'user',
|
|
240
|
-
label: translateTaskText(t, 'orchestration.chat.user.step', '需求 {count}', { count: 1 }),
|
|
241
|
-
text: target,
|
|
242
|
-
meta: translateTaskText(t, 'orchestration.chat.meta.first', '先完成这一条')
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
followUps.forEach((item, index) => {
|
|
246
|
-
const step = index + 2;
|
|
247
|
-
messages.push({
|
|
248
|
-
id: `user-follow-up-${index}`,
|
|
249
|
-
role: 'user',
|
|
250
|
-
label: translateTaskText(t, 'orchestration.chat.user.step', '需求 {count}', { count: step }),
|
|
251
|
-
text: item,
|
|
252
|
-
meta: translateTaskText(t, 'orchestration.chat.meta.afterPrevious', '等待前一条完成后继续')
|
|
253
|
-
});
|
|
254
|
-
});
|
|
255
|
-
if (!state.plan && target) {
|
|
256
|
-
messages.push({
|
|
257
|
-
id: 'assistant-next',
|
|
258
|
-
role: 'assistant',
|
|
259
|
-
label: translateTaskText(t, 'orchestration.chat.assistant.readyLabel', 'Codexmate'),
|
|
260
|
-
text: followUps.length > 0
|
|
261
|
-
? translateTaskText(t, 'orchestration.chat.assistant.sequenceReady', '已收到多条需求;执行时会先完成需求 1,再带着上下文继续后续需求。')
|
|
262
|
-
: translateTaskText(t, 'orchestration.chat.assistant.singleReady', '已收到第一条需求。可以继续补需求 2,或直接预览并执行。'),
|
|
263
|
-
meta: translateTaskText(t, 'orchestration.chat.meta.previewNext', '下一步:预览计划')
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
return messages;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
function translateTaskText(t, key, fallback, params = null) {
|
|
270
|
-
if (typeof t !== 'function') return fallback;
|
|
271
|
-
const translated = t(key, params);
|
|
272
|
-
return translated === key ? fallback : translated;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function createTaskDraftChecklist(metrics, t = null) {
|
|
276
|
-
const workflowReady = metrics.engine !== 'workflow' || metrics.workflowCount > 0;
|
|
277
|
-
const scopeReady = metrics.hasNotes || !metrics.allowWrite;
|
|
278
|
-
const previewReady = metrics.hasPlan && metrics.planIssues.length === 0;
|
|
279
|
-
return [
|
|
280
|
-
{
|
|
281
|
-
key: 'target',
|
|
282
|
-
label: translateTaskText(t, 'orchestration.readiness.target.label', '目标'),
|
|
283
|
-
done: metrics.hasTarget,
|
|
284
|
-
detail: metrics.hasTarget ? translateTaskText(t, 'orchestration.readiness.target.done', '已写目标') : translateTaskText(t, 'orchestration.readiness.target.missing', '还没写目标')
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
key: 'sequence',
|
|
288
|
-
label: translateTaskText(t, 'orchestration.readiness.sequence.label', '顺序'),
|
|
289
|
-
done: metrics.hasTarget,
|
|
290
|
-
detail: !metrics.hasTarget
|
|
291
|
-
? translateTaskText(t, 'orchestration.readiness.sequence.missing', '先发送需求 1')
|
|
292
|
-
: (metrics.hasSequentialFollowUps
|
|
293
|
-
? translateTaskText(t, 'orchestration.readiness.sequence.multiple', '{count} 条需求会按顺序执行:先完成需求 1,再继续需求 2。', { count: metrics.requestCount })
|
|
294
|
-
: translateTaskText(t, 'orchestration.readiness.sequence.single', '当前只有需求 1;继续发送会变成需求 2。'))
|
|
295
|
-
},
|
|
296
|
-
{
|
|
297
|
-
key: 'engine',
|
|
298
|
-
label: metrics.engine === 'workflow' ? 'Workflow' : translateTaskText(t, 'orchestration.readiness.engine.label', '执行策略'),
|
|
299
|
-
done: workflowReady,
|
|
300
|
-
detail: metrics.engine === 'workflow'
|
|
301
|
-
? (metrics.workflowCount > 0 ? translateTaskText(t, 'orchestration.readiness.workflow.done', `已选 ${metrics.workflowCount} 个 Workflow`, { count: metrics.workflowCount }) : translateTaskText(t, 'orchestration.readiness.workflow.missing', '还没选 Workflow ID'))
|
|
302
|
-
: translateTaskText(t, 'orchestration.readiness.engine.openaiChat', '使用 OpenAI Chat-compatible 节点')
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
key: 'scope',
|
|
306
|
-
label: translateTaskText(t, 'orchestration.readiness.scope.label', '边界'),
|
|
307
|
-
done: scopeReady,
|
|
308
|
-
detail: metrics.hasNotes
|
|
309
|
-
? translateTaskText(t, 'orchestration.readiness.scope.done', '已补充说明')
|
|
310
|
-
: (metrics.allowWrite ? translateTaskText(t, 'orchestration.readiness.scope.writeHint', '建议补说明后再写入') : translateTaskText(t, 'orchestration.readiness.scope.readonlyHint', '当前是只读,可直接试'))
|
|
311
|
-
},
|
|
312
|
-
{
|
|
313
|
-
key: 'preview',
|
|
314
|
-
label: translateTaskText(t, 'orchestration.readiness.preview.label', '预览'),
|
|
315
|
-
done: previewReady,
|
|
316
|
-
detail: !metrics.hasPlan
|
|
317
|
-
? translateTaskText(t, 'orchestration.readiness.preview.missing', '还没发送 /plan')
|
|
318
|
-
: (metrics.planIssues.length > 0 ? translateTaskText(t, 'orchestration.readiness.preview.blocked', `有 ${metrics.planIssues.length} 个阻塞项`, { count: metrics.planIssues.length }) : translateTaskText(t, 'orchestration.readiness.preview.ready', `计划可用,${metrics.planNodeCount} 个节点`, { count: metrics.planNodeCount }))
|
|
319
|
-
}
|
|
320
|
-
];
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
function createTaskDraftReadiness(metrics, t = null) {
|
|
324
|
-
if (!metrics.hasTarget) {
|
|
325
|
-
return {
|
|
326
|
-
tone: 'neutral',
|
|
327
|
-
title: translateTaskText(t, 'orchestration.readiness.empty.title', '先写目标'),
|
|
328
|
-
summary: translateTaskText(t, 'orchestration.readiness.empty.summary', '先把想完成的结果写清楚,再让编排器拆节点。')
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
if (metrics.engine === 'workflow' && metrics.workflowCount === 0) {
|
|
332
|
-
return {
|
|
333
|
-
tone: 'warn',
|
|
334
|
-
title: translateTaskText(t, 'orchestration.readiness.workflow.title', '缺少 Workflow'),
|
|
335
|
-
summary: translateTaskText(t, 'orchestration.readiness.workflow.summary', '你已经选了 Workflow 模式,但还没指定可复用流程。')
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
if (!metrics.hasPlan) {
|
|
339
|
-
return {
|
|
340
|
-
tone: 'warn',
|
|
341
|
-
title: translateTaskText(t, 'orchestration.readiness.preview.title', '建议先预览'),
|
|
342
|
-
summary: metrics.hasSequentialFollowUps
|
|
343
|
-
? translateTaskText(t, 'orchestration.readiness.preview.sequenceSummary', '草稿已成形,已锁定 {count} 条顺序需求:先完成需求 1,再继续需求 2。', { count: metrics.requestCount })
|
|
344
|
-
: translateTaskText(t, 'orchestration.readiness.preview.summary', '草稿已成形,发送 /plan 预览方案,确认节点和依赖再执行。')
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
if (metrics.planIssues.length > 0) {
|
|
348
|
-
return {
|
|
349
|
-
tone: 'error',
|
|
350
|
-
title: translateTaskText(t, 'orchestration.readiness.blocked.title', '预览有阻塞'),
|
|
351
|
-
summary: translateTaskText(t, 'orchestration.readiness.blocked.summary', `当前计划里还有 ${metrics.planIssues.length} 个阻塞项,先处理它们。`, { count: metrics.planIssues.length })
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
if (metrics.planWarnings.length > 0) {
|
|
355
|
-
return {
|
|
356
|
-
tone: 'warn',
|
|
357
|
-
title: translateTaskText(t, 'orchestration.readiness.warn.title', '可以执行,但有提醒'),
|
|
358
|
-
summary: translateTaskText(t, 'orchestration.readiness.warn.summary', `/plan 方案已生成,但还有 ${metrics.planWarnings.length} 条提醒值得先看一眼。`, { count: metrics.planWarnings.length })
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
if (metrics.dryRun) {
|
|
362
|
-
return {
|
|
363
|
-
tone: 'success',
|
|
364
|
-
title: translateTaskText(t, 'orchestration.readiness.dryRun.title', '适合先预演'),
|
|
365
|
-
summary: translateTaskText(t, 'orchestration.readiness.dryRun.summary', '现在可以安全地跑一次仅预演,先看结果再决定是否真实执行。')
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
return {
|
|
369
|
-
tone: 'success',
|
|
370
|
-
title: translateTaskText(t, 'orchestration.readiness.ready.title', '可以执行'),
|
|
371
|
-
summary: metrics.followUpCount > 0
|
|
372
|
-
? translateTaskText(t, 'orchestration.readiness.ready.withFollowUps', `已锁定 ${metrics.requestCount} 条顺序需求:先完成需求 1,再带上下文继续需求 2。`, { count: metrics.requestCount })
|
|
373
|
-
: translateTaskText(t, 'orchestration.readiness.ready.summary', '主目标已经够清楚了,可以直接执行或入队。')
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
|
|
377
1
|
export function createMainTabsComputed() {
|
|
378
2
|
return {
|
|
379
3
|
mainTabKicker() {
|
|
@@ -381,7 +5,6 @@ export function createMainTabsComputed() {
|
|
|
381
5
|
if (this.mainTab === 'config') return this.t('kicker.config');
|
|
382
6
|
if (this.mainTab === 'sessions') return this.t('kicker.sessions');
|
|
383
7
|
if (this.mainTab === 'usage') return this.t('kicker.usage');
|
|
384
|
-
if (this.mainTab === 'orchestration') return this.t('kicker.orchestration');
|
|
385
8
|
if (this.mainTab === 'market') return this.t('kicker.market');
|
|
386
9
|
if (this.mainTab === 'plugins') return this.t('kicker.plugins');
|
|
387
10
|
if (this.mainTab === 'docs') return this.t('kicker.docs');
|
|
@@ -394,7 +17,6 @@ export function createMainTabsComputed() {
|
|
|
394
17
|
if (this.mainTab === 'config') return this.t('title.config');
|
|
395
18
|
if (this.mainTab === 'sessions') return this.t('title.sessions');
|
|
396
19
|
if (this.mainTab === 'usage') return this.t('title.usage');
|
|
397
|
-
if (this.mainTab === 'orchestration') return this.t('title.orchestration');
|
|
398
20
|
if (this.mainTab === 'market') return this.t('title.market');
|
|
399
21
|
if (this.mainTab === 'plugins') return this.t('title.plugins');
|
|
400
22
|
if (this.mainTab === 'docs') return this.t('title.docs');
|
|
@@ -407,108 +29,12 @@ export function createMainTabsComputed() {
|
|
|
407
29
|
if (this.mainTab === 'config') return this.t('subtitle.config');
|
|
408
30
|
if (this.mainTab === 'sessions') return this.t('subtitle.sessions');
|
|
409
31
|
if (this.mainTab === 'usage') return this.t('subtitle.usage');
|
|
410
|
-
if (this.mainTab === 'orchestration') return this.t('subtitle.orchestration');
|
|
411
32
|
if (this.mainTab === 'market') return this.t('subtitle.market');
|
|
412
33
|
if (this.mainTab === 'plugins') return this.t('subtitle.plugins');
|
|
413
34
|
if (this.mainTab === 'docs') return this.t('subtitle.docs');
|
|
414
35
|
if (this.mainTab === 'trash') return this.t('settings.trash.meta');
|
|
415
36
|
if (this.mainTab === 'prompts') return this.t('subtitle.prompts');
|
|
416
37
|
return this.t('subtitle.settings');
|
|
417
|
-
},
|
|
418
|
-
taskOrchestrationSelectedRun() {
|
|
419
|
-
return this.taskOrchestration && this.taskOrchestration.selectedRunDetail
|
|
420
|
-
? this.taskOrchestration.selectedRunDetail
|
|
421
|
-
: null;
|
|
422
|
-
},
|
|
423
|
-
taskOrchestrationSelectedRunNodes() {
|
|
424
|
-
const detail = this.taskOrchestrationSelectedRun;
|
|
425
|
-
const run = detail && detail.run && typeof detail.run === 'object' ? detail.run : {};
|
|
426
|
-
if (detail && Array.isArray(detail.nodes)) return detail.nodes;
|
|
427
|
-
return Array.isArray(run.nodes) ? run.nodes : [];
|
|
428
|
-
},
|
|
429
|
-
taskOrchestrationActiveQueue() {
|
|
430
|
-
const queue = this.taskOrchestration && Array.isArray(this.taskOrchestration.queue)
|
|
431
|
-
? this.taskOrchestration.queue
|
|
432
|
-
: [];
|
|
433
|
-
return queue.filter((item) => {
|
|
434
|
-
const status = String((item && (item.status || item.runStatus)) || '').trim().toLowerCase();
|
|
435
|
-
return status === 'queued' || status === 'running';
|
|
436
|
-
});
|
|
437
|
-
},
|
|
438
|
-
taskOrchestrationEngineLabel() {
|
|
439
|
-
const state = this.taskOrchestration && typeof this.taskOrchestration === 'object'
|
|
440
|
-
? this.taskOrchestration
|
|
441
|
-
: {};
|
|
442
|
-
return state.selectedEngine === 'workflow' ? 'Workflow' : 'Codex';
|
|
443
|
-
},
|
|
444
|
-
taskOrchestrationWorkbenchVisible() {
|
|
445
|
-
const state = this.taskOrchestration && typeof this.taskOrchestration === 'object'
|
|
446
|
-
? this.taskOrchestration
|
|
447
|
-
: {};
|
|
448
|
-
const activeQueue = Array.isArray(this.taskOrchestrationActiveQueue)
|
|
449
|
-
? this.taskOrchestrationActiveQueue
|
|
450
|
-
: [];
|
|
451
|
-
return activeQueue.length > 0
|
|
452
|
-
|| !!String(state.selectedRunId || '').trim()
|
|
453
|
-
|| !!String(state.selectedRunError || '').trim()
|
|
454
|
-
|| (state.workspaceTab === 'runs' && Array.isArray(state.runs) && state.runs.length > 0);
|
|
455
|
-
},
|
|
456
|
-
taskOrchestrationWorkspacePath() {
|
|
457
|
-
const state = this.taskOrchestration && typeof this.taskOrchestration === 'object'
|
|
458
|
-
? this.taskOrchestration
|
|
459
|
-
: {};
|
|
460
|
-
const detail = state.selectedRunDetail && typeof state.selectedRunDetail === 'object'
|
|
461
|
-
? state.selectedRunDetail
|
|
462
|
-
: null;
|
|
463
|
-
return normalizeTaskWorkspacePath(state.workspacePath || (detail && detail.cwd) || '');
|
|
464
|
-
},
|
|
465
|
-
taskOrchestrationWorkspaceItems() {
|
|
466
|
-
const items = createTaskWorkspaceItems(this.taskOrchestration);
|
|
467
|
-
const selectedPath = this.taskOrchestrationWorkspacePath;
|
|
468
|
-
return items.map((item) => ({
|
|
469
|
-
...item,
|
|
470
|
-
active: normalizeTaskWorkspacePath(item.path) === selectedPath || (!selectedPath && !item.path)
|
|
471
|
-
}));
|
|
472
|
-
},
|
|
473
|
-
taskOrchestrationWorkspaceQueue() {
|
|
474
|
-
const queue = this.taskOrchestration && Array.isArray(this.taskOrchestration.queue)
|
|
475
|
-
? this.taskOrchestration.queue
|
|
476
|
-
: [];
|
|
477
|
-
return queue.filter((item) => taskItemMatchesWorkspace(item, this.taskOrchestrationWorkspacePath));
|
|
478
|
-
},
|
|
479
|
-
taskOrchestrationWorkspaceRuns() {
|
|
480
|
-
const runs = this.taskOrchestration && Array.isArray(this.taskOrchestration.runs)
|
|
481
|
-
? this.taskOrchestration.runs
|
|
482
|
-
: [];
|
|
483
|
-
return runs.filter((item) => taskItemMatchesWorkspace(item, this.taskOrchestrationWorkspacePath));
|
|
484
|
-
},
|
|
485
|
-
taskOrchestrationWorkspaceSessions() {
|
|
486
|
-
return createTaskWorkspaceSessions(this.taskOrchestration, this.taskOrchestrationWorkspacePath);
|
|
487
|
-
},
|
|
488
|
-
taskOrchestrationQueueStats() {
|
|
489
|
-
const queue = this.taskOrchestration && Array.isArray(this.taskOrchestration.queue)
|
|
490
|
-
? this.taskOrchestration.queue
|
|
491
|
-
: [];
|
|
492
|
-
const stats = { queued: 0, running: 0, failed: 0 };
|
|
493
|
-
for (const item of queue) {
|
|
494
|
-
const status = String((item && (item.status || item.runStatus)) || '').trim().toLowerCase();
|
|
495
|
-
if (status === 'queued') stats.queued += 1;
|
|
496
|
-
else if (status === 'running') stats.running += 1;
|
|
497
|
-
else if (status === 'failed') stats.failed += 1;
|
|
498
|
-
}
|
|
499
|
-
return stats;
|
|
500
|
-
},
|
|
501
|
-
taskOrchestrationDraftMetrics() {
|
|
502
|
-
return readTaskOrchestrationDraftMetrics(this.taskOrchestration);
|
|
503
|
-
},
|
|
504
|
-
taskOrchestrationDraftChecklist() {
|
|
505
|
-
return createTaskDraftChecklist(this.taskOrchestrationDraftMetrics, this.t && this.t.bind(this));
|
|
506
|
-
},
|
|
507
|
-
taskOrchestrationDraftReadiness() {
|
|
508
|
-
return createTaskDraftReadiness(this.taskOrchestrationDraftMetrics, this.t && this.t.bind(this));
|
|
509
|
-
},
|
|
510
|
-
taskOrchestrationConversationMessages() {
|
|
511
|
-
return createTaskConversationMessages(this.taskOrchestration, this.t && this.t.bind(this));
|
|
512
38
|
}
|
|
513
39
|
};
|
|
514
40
|
}
|
|
@@ -26,7 +26,6 @@ import { createProvidersMethods } from './app.methods.providers.mjs';
|
|
|
26
26
|
import { createProviderCacheMethods } from './app.methods.provider-cache.mjs';
|
|
27
27
|
import { createRuntimeMethods } from './app.methods.runtime.mjs';
|
|
28
28
|
import { createToolConfigPermissionMethods } from './app.methods.tool-config-permissions.mjs';
|
|
29
|
-
import { createTaskOrchestrationMethods } from './app.methods.task-orchestration.mjs';
|
|
30
29
|
import { createSessionActionMethods } from './app.methods.session-actions.mjs';
|
|
31
30
|
import { createSessionBrowserMethods } from './app.methods.session-browser.mjs';
|
|
32
31
|
import { createSessionTimelineMethods } from './app.methods.session-timeline.mjs';
|
|
@@ -104,7 +103,6 @@ export function createAppMethods() {
|
|
|
104
103
|
}),
|
|
105
104
|
...createKilocodeConfigMethods({ api }),
|
|
106
105
|
...createInstallMethods({ api }),
|
|
107
|
-
...createRuntimeMethods({ api })
|
|
108
|
-
...createTaskOrchestrationMethods({ api })
|
|
106
|
+
...createRuntimeMethods({ api })
|
|
109
107
|
};
|
|
110
108
|
}
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
'config',
|
|
10
10
|
'sessions',
|
|
11
11
|
'usage',
|
|
12
|
-
'orchestration',
|
|
13
12
|
'market',
|
|
14
13
|
'plugins',
|
|
15
14
|
'docs',
|
|
@@ -18,7 +17,7 @@
|
|
|
18
17
|
'prompts'
|
|
19
18
|
];
|
|
20
19
|
const MAIN_TAB_SET = new Set(MAIN_TAB_ORDER);
|
|
21
|
-
const DISABLED_MAIN_TAB_SET = new Set(
|
|
20
|
+
const DISABLED_MAIN_TAB_SET = new Set();
|
|
22
21
|
const normalizeMainTab = (tab) => typeof tab === 'string'
|
|
23
22
|
? tab.trim().toLowerCase()
|
|
24
23
|
: '';
|