chainlesschain 0.45.81 → 0.47.0
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 +10 -0
- package/bin/chainlesschain.js +0 -0
- package/package.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{Analytics-C1AnPdMx.js → Analytics-DgypYeUB.js} +2 -2
- package/src/assets/web-panel/assets/AppLayout-Bzf3mSZI.js +1 -0
- package/src/assets/web-panel/assets/AppLayout-DQyDwGut.css +1 -0
- package/src/assets/web-panel/assets/{Backup-D31iZX3l.js → Backup-Ba9UybpT.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-DiXJ3TuK.js → Chat-BwXskT21.js} +1 -1
- package/src/assets/web-panel/assets/Cowork-CXuhlHew.css +1 -0
- package/src/assets/web-panel/assets/Cowork-UmOe7qvE.js +7 -0
- package/src/assets/web-panel/assets/{Cron-DBt1ueXh.js → Cron-JHS-rc-4.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-HPh9FcPt.js → Dashboard-B95cMCO7.js} +2 -2
- package/src/assets/web-panel/assets/Dashboard-CKeMmCoT.css +1 -0
- package/src/assets/web-panel/assets/{Git-hwQ1oZHj.js → Git-CSYO0_zk.js} +2 -2
- package/src/assets/web-panel/assets/{Logs-4D9p6PRM.js → Logs-Hxw_K0km.js} +2 -2
- package/src/assets/web-panel/assets/{McpTools-CyAUjbbs.js → McpTools-DIE75TrB.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-BMqOR7S-.js → Memory-C4KVnLlp.js} +2 -2
- package/src/assets/web-panel/assets/{Notes-Cmas8i4E.js → Notes-DuzrHMAk.js} +2 -2
- package/src/assets/web-panel/assets/{Organization-DnSa58Tl.js → Organization-DTq6uF82.js} +4 -4
- package/src/assets/web-panel/assets/{P2P-BxksIBWs.js → P2P-C0hjlhsR.js} +2 -2
- package/src/assets/web-panel/assets/{Permissions-Bq5Qn2s3.js → Permissions-Ec0NH-xC.js} +4 -4
- package/src/assets/web-panel/assets/{Projects-B7EM0uPg.js → Projects-U8D0asCS.js} +2 -2
- package/src/assets/web-panel/assets/{Providers-DAwgG5KV.js → Providers-BngtTLvJ.js} +2 -2
- package/src/assets/web-panel/assets/{RssFeed-HSZoRXvS.js → RssFeed-B9NbwCKM.js} +3 -3
- package/src/assets/web-panel/assets/{Security-Cz17qBny.js → Security-BL5Rkr1T.js} +3 -3
- package/src/assets/web-panel/assets/{Services-D2EsLq-v.js → Services-D4MJzLld.js} +2 -2
- package/src/assets/web-panel/assets/{Skills-C9v-f3vZ.js → Skills-CQTOMDwF.js} +1 -1
- package/src/assets/web-panel/assets/{Tasks-yMEcU0n7.js → Tasks-DepbJMnL.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-l7SvlKuB.js → Templates-C24PVZPu.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BHWhLWn9.js → Wallet-PQoSpN_P.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-kWhFYaUK.js → WebAuthn-BcuyQ4Lr.js} +4 -4
- package/src/assets/web-panel/assets/WorkflowEditor-C-SvXbHW.js +1 -0
- package/src/assets/web-panel/assets/WorkflowEditor-D5bX6woe.css +1 -0
- package/src/assets/web-panel/assets/{antd-D6h4fDFf.js → antd-DEjZPGMj.js} +82 -82
- package/src/assets/web-panel/assets/index-CwvzTTw_.js +2 -0
- package/src/assets/web-panel/assets/{markdown-BZsB-Dsv.js → markdown-CusdXFxb.js} +1 -1
- package/src/assets/web-panel/index.html +2 -2
- package/src/commands/cowork.js +867 -0
- package/src/gateways/ws/action-protocol.js +182 -2
- package/src/gateways/ws/message-dispatcher.js +5 -0
- package/src/gateways/ws/ws-server.js +21 -0
- package/src/lib/cowork-cron.js +474 -0
- package/src/lib/cowork-evomap-adapter.js +121 -0
- package/src/lib/cowork-learning.js +438 -0
- package/src/lib/cowork-mcp-tools.js +182 -0
- package/src/lib/cowork-observe-html.js +108 -0
- package/src/lib/cowork-observe.js +160 -0
- package/src/lib/cowork-share.js +322 -0
- package/src/lib/cowork-task-runner.js +317 -3
- package/src/lib/cowork-task-templates.js +101 -13
- package/src/lib/cowork-template-marketplace.js +205 -0
- package/src/lib/cowork-workflow.js +571 -0
- package/src/lib/provider-options.js +133 -0
- package/src/lib/skill-loader.js +65 -0
- package/src/lib/sub-agent-context.js +54 -2
- package/src/lib/sub-agent-profiles.js +164 -0
- package/src/lib/todo-manager.js +108 -0
- package/src/lib/turn-context.js +95 -0
- package/src/lib/web-fetch.js +224 -0
- package/src/lib/workflow-expr.js +318 -0
- package/src/repl/agent-repl.js +4 -0
- package/src/runtime/agent-core.js +135 -3
- package/src/runtime/coding-agent-contract-shared.cjs +131 -0
- package/src/runtime/coding-agent-policy.cjs +30 -0
- package/src/assets/web-panel/assets/AppLayout-YdvJBMHH.js +0 -1
- package/src/assets/web-panel/assets/AppLayout-cxfKLu-m.css +0 -1
- package/src/assets/web-panel/assets/Cowork-BnrHWwZw.js +0 -7
- package/src/assets/web-panel/assets/Cowork-CcSoS3eX.css +0 -1
- package/src/assets/web-panel/assets/Dashboard-BS-tzGNj.css +0 -1
- package/src/assets/web-panel/assets/index-ByUk2Wmr.js +0 -2
|
@@ -7,14 +7,16 @@
|
|
|
7
7
|
* @module cowork-task-runner
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { existsSync, mkdirSync, appendFileSync } from "node:fs";
|
|
10
|
+
import { existsSync, mkdirSync, appendFileSync, readFileSync } from "node:fs";
|
|
11
11
|
import { join } from "node:path";
|
|
12
12
|
import { SubAgentContext } from "./sub-agent-context.js";
|
|
13
|
-
import { getTemplate } from "./cowork-task-templates.js";
|
|
13
|
+
import { getTemplate, setUserTemplates } from "./cowork-task-templates.js";
|
|
14
|
+
import { mountTemplateMcpTools } from "./cowork-mcp-tools.js";
|
|
15
|
+
import { listUserTemplates } from "./cowork-template-marketplace.js";
|
|
14
16
|
|
|
15
17
|
// ─── Dependencies (overridable for testing) ──────────────────────────────────
|
|
16
18
|
|
|
17
|
-
export const _deps = { existsSync, mkdirSync, appendFileSync };
|
|
19
|
+
export const _deps = { existsSync, mkdirSync, appendFileSync, readFileSync };
|
|
18
20
|
|
|
19
21
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
20
22
|
|
|
@@ -63,18 +65,53 @@ export async function runCoworkTask(options = {}) {
|
|
|
63
65
|
}
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
// Merge user-installed templates (marketplace) into the registry before resolving
|
|
69
|
+
try {
|
|
70
|
+
setUserTemplates(listUserTemplates(cwd));
|
|
71
|
+
} catch (_e) {
|
|
72
|
+
// Non-fatal — marketplace absence should not break task execution
|
|
73
|
+
}
|
|
74
|
+
|
|
66
75
|
// Resolve template
|
|
67
76
|
const template = getTemplate(templateId);
|
|
68
77
|
|
|
69
78
|
// Build the task prompt with template context + files
|
|
70
79
|
const taskParts = [template.systemPromptExtension];
|
|
71
80
|
|
|
81
|
+
// N2: apply learning-layer patch for this template if one exists
|
|
82
|
+
try {
|
|
83
|
+
const { loadUserTemplate } = await import("./cowork-learning.js");
|
|
84
|
+
const override = loadUserTemplate(cwd, template.id);
|
|
85
|
+
if (override?.systemPromptExtension) {
|
|
86
|
+
taskParts.push(
|
|
87
|
+
`\n## 历史学习补丁 (learning patch)\n${override.systemPromptExtension}`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
} catch (_e) {
|
|
91
|
+
// Non-fatal — learning overrides are optional
|
|
92
|
+
}
|
|
93
|
+
|
|
72
94
|
if (files.length > 0) {
|
|
73
95
|
taskParts.push(`\n## 用户提供的文件\n${files.join("\n")}`);
|
|
74
96
|
}
|
|
75
97
|
|
|
76
98
|
const task = taskParts.join("\n");
|
|
77
99
|
|
|
100
|
+
// Mount template-declared MCP servers (best-effort, failures are tolerated)
|
|
101
|
+
const mcp = await mountTemplateMcpTools(template, {
|
|
102
|
+
onWarn: (msg) => {
|
|
103
|
+
if (onProgress) onProgress({ type: "mcp-warning", message: msg });
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
if (onProgress && (mcp.mounted.length > 0 || mcp.skipped.length > 0)) {
|
|
107
|
+
onProgress({
|
|
108
|
+
type: "mcp-mounted",
|
|
109
|
+
mounted: mcp.mounted,
|
|
110
|
+
skipped: mcp.skipped.map((s) => s.name),
|
|
111
|
+
toolCount: mcp.extraToolDefinitions.length,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
78
115
|
// Create isolated sub-agent context
|
|
79
116
|
const subAgent = SubAgentContext.create({
|
|
80
117
|
role: `cowork-${template.id}`,
|
|
@@ -87,6 +124,10 @@ export async function runCoworkTask(options = {}) {
|
|
|
87
124
|
cwd,
|
|
88
125
|
onProgress,
|
|
89
126
|
signal,
|
|
127
|
+
extraToolDefinitions: mcp.extraToolDefinitions,
|
|
128
|
+
externalToolDescriptors: mcp.externalToolDescriptors,
|
|
129
|
+
externalToolExecutors: mcp.externalToolExecutors,
|
|
130
|
+
mcpClient: mcp.mcpClient,
|
|
90
131
|
});
|
|
91
132
|
|
|
92
133
|
const taskId = subAgent.id;
|
|
@@ -128,6 +169,279 @@ export async function runCoworkTask(options = {}) {
|
|
|
128
169
|
};
|
|
129
170
|
_appendHistory(cwd, entry, userMessage);
|
|
130
171
|
return entry;
|
|
172
|
+
} finally {
|
|
173
|
+
await mcp.cleanup();
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ─── Parallel Runner (Orchestrator) ──────────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Run a cowork task using the Orchestrator for multi-agent parallel execution.
|
|
181
|
+
*
|
|
182
|
+
* @param {object} options - Same as runCoworkTask, plus:
|
|
183
|
+
* @param {number} [options.agents] - Number of parallel agents (default 3, max 10)
|
|
184
|
+
* @param {string} [options.strategy] - Routing strategy (default "round-robin")
|
|
185
|
+
* @param {function} [options.onProgress] - Progress callback
|
|
186
|
+
* @param {AbortSignal} [options.signal] - Cancellation signal
|
|
187
|
+
* @returns {Promise<{ taskId: string, status: string, result: object }>}
|
|
188
|
+
*/
|
|
189
|
+
export async function runCoworkTaskParallel(options = {}) {
|
|
190
|
+
const {
|
|
191
|
+
templateId = null,
|
|
192
|
+
userMessage,
|
|
193
|
+
files = [],
|
|
194
|
+
cwd = process.cwd(),
|
|
195
|
+
agents = 3,
|
|
196
|
+
strategy,
|
|
197
|
+
onProgress = null,
|
|
198
|
+
signal = null,
|
|
199
|
+
} = options;
|
|
200
|
+
|
|
201
|
+
if (!userMessage || typeof userMessage !== "string") {
|
|
202
|
+
throw new Error("userMessage is required");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (files.length > 0) {
|
|
206
|
+
const missing = files.filter((f) => !_deps.existsSync(f));
|
|
207
|
+
if (missing.length > 0) {
|
|
208
|
+
throw new Error(`File(s) not found: ${missing.join(", ")}`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const template = getTemplate(templateId);
|
|
213
|
+
|
|
214
|
+
// Build full task description for the orchestrator
|
|
215
|
+
const taskParts = [
|
|
216
|
+
`[Cowork Template: ${template.name}]`,
|
|
217
|
+
template.systemPromptExtension,
|
|
218
|
+
`\n## 用户需求\n${userMessage}`,
|
|
219
|
+
];
|
|
220
|
+
if (files.length > 0) {
|
|
221
|
+
taskParts.push(`\n## 用户提供的文件\n${files.join("\n")}`);
|
|
222
|
+
}
|
|
223
|
+
const fullTask = taskParts.join("\n");
|
|
224
|
+
|
|
225
|
+
try {
|
|
226
|
+
const { Orchestrator, TASK_SOURCE } = await import("./orchestrator.js");
|
|
227
|
+
|
|
228
|
+
const orch = new Orchestrator({
|
|
229
|
+
cwd,
|
|
230
|
+
maxParallel: Math.min(parseInt(agents, 10) || 3, 10),
|
|
231
|
+
ciCommand: "echo ok",
|
|
232
|
+
agents: strategy ? { strategy } : undefined,
|
|
233
|
+
verbose: false,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Wire progress events
|
|
237
|
+
if (onProgress) {
|
|
238
|
+
orch.on("task:added", (t) =>
|
|
239
|
+
onProgress({
|
|
240
|
+
type: "orchestrator-started",
|
|
241
|
+
taskId: t.id,
|
|
242
|
+
subtaskCount: 0,
|
|
243
|
+
}),
|
|
244
|
+
);
|
|
245
|
+
orch.on("task:decomposed", (t) =>
|
|
246
|
+
onProgress({
|
|
247
|
+
type: "orchestrator-decomposed",
|
|
248
|
+
taskId: t.id,
|
|
249
|
+
subtaskCount: t.subtasks?.length || 0,
|
|
250
|
+
}),
|
|
251
|
+
);
|
|
252
|
+
orch.on("agents:dispatched", (ev) =>
|
|
253
|
+
onProgress({
|
|
254
|
+
type: "agents-dispatched",
|
|
255
|
+
agentCount: ev.agents?.length || 0,
|
|
256
|
+
}),
|
|
257
|
+
);
|
|
258
|
+
orch.on("agent:output", (ev) =>
|
|
259
|
+
onProgress({
|
|
260
|
+
type: "agent-progress",
|
|
261
|
+
agentIndex: ev.agentIndex,
|
|
262
|
+
status: ev.status,
|
|
263
|
+
output: ev.output?.slice(0, 200),
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Handle cancellation
|
|
269
|
+
if (signal) {
|
|
270
|
+
signal.addEventListener(
|
|
271
|
+
"abort",
|
|
272
|
+
() => {
|
|
273
|
+
orch.stopCronWatch();
|
|
274
|
+
},
|
|
275
|
+
{ once: true },
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
const orchResult = await orch.addTask(fullTask, {
|
|
280
|
+
source: TASK_SOURCE.CLI,
|
|
281
|
+
cwd,
|
|
282
|
+
runCI: false,
|
|
283
|
+
notify: false,
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
const entry = {
|
|
287
|
+
taskId: orchResult.id,
|
|
288
|
+
status: orchResult.status === "completed" ? "completed" : "failed",
|
|
289
|
+
templateId: template.id,
|
|
290
|
+
templateName: template.name,
|
|
291
|
+
parallel: true,
|
|
292
|
+
agentCount: agents,
|
|
293
|
+
result: {
|
|
294
|
+
summary:
|
|
295
|
+
orchResult.agentResults
|
|
296
|
+
?.map((r) => r.output?.slice(0, 500))
|
|
297
|
+
.join("\n---\n") || "Parallel execution completed",
|
|
298
|
+
artifacts: [],
|
|
299
|
+
tokenCount: 0,
|
|
300
|
+
toolsUsed: [],
|
|
301
|
+
iterationCount: orchResult.retries || 0,
|
|
302
|
+
subtaskCount: orchResult.subtasks?.length || 0,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
_appendHistory(cwd, entry, userMessage);
|
|
306
|
+
return entry;
|
|
307
|
+
} catch (err) {
|
|
308
|
+
const entry = {
|
|
309
|
+
taskId: `cowork-parallel-${Date.now()}`,
|
|
310
|
+
status: "failed",
|
|
311
|
+
templateId: template.id,
|
|
312
|
+
templateName: template.name,
|
|
313
|
+
parallel: true,
|
|
314
|
+
result: {
|
|
315
|
+
summary: `Parallel task failed: ${err.message}`,
|
|
316
|
+
artifacts: [],
|
|
317
|
+
tokenCount: 0,
|
|
318
|
+
toolsUsed: [],
|
|
319
|
+
iterationCount: 0,
|
|
320
|
+
subtaskCount: 0,
|
|
321
|
+
},
|
|
322
|
+
};
|
|
323
|
+
_appendHistory(cwd, entry, userMessage);
|
|
324
|
+
return entry;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// ─── Debate Runner (Multi-perspective Review) ───────────────────────────────
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Run a cowork task in debate mode — multiple reviewer perspectives converge
|
|
332
|
+
* into a final verdict via moderator synthesis.
|
|
333
|
+
*
|
|
334
|
+
* @param {object} options
|
|
335
|
+
* @param {string|null} options.templateId - Should be "code-review" or null
|
|
336
|
+
* @param {string} options.userMessage - Target description / review instructions
|
|
337
|
+
* @param {string[]} [options.files] - File paths to review (concatenated as code body)
|
|
338
|
+
* @param {string[]} [options.perspectives] - Override template perspectives
|
|
339
|
+
* @param {string} [options.cwd] - Working directory for history
|
|
340
|
+
* @param {object} [options.llmOptions] - LLM provider/model/key
|
|
341
|
+
* @param {function} [options.onProgress] - Progress callback
|
|
342
|
+
* @returns {Promise<{ taskId, status, result }>}
|
|
343
|
+
*/
|
|
344
|
+
export async function runCoworkDebate(options = {}) {
|
|
345
|
+
const {
|
|
346
|
+
templateId = "code-review",
|
|
347
|
+
userMessage,
|
|
348
|
+
files = [],
|
|
349
|
+
perspectives,
|
|
350
|
+
cwd = process.cwd(),
|
|
351
|
+
llmOptions = {},
|
|
352
|
+
onProgress = null,
|
|
353
|
+
} = options;
|
|
354
|
+
|
|
355
|
+
if (!userMessage || typeof userMessage !== "string") {
|
|
356
|
+
throw new Error("userMessage is required");
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (files.length > 0) {
|
|
360
|
+
const missing = files.filter((f) => !_deps.existsSync(f));
|
|
361
|
+
if (missing.length > 0) {
|
|
362
|
+
throw new Error(`File(s) not found: ${missing.join(", ")}`);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
const template = getTemplate(templateId);
|
|
367
|
+
const reviewPerspectives = perspectives ||
|
|
368
|
+
template.debatePerspectives || [
|
|
369
|
+
"performance",
|
|
370
|
+
"security",
|
|
371
|
+
"maintainability",
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
// Build code body from files (or from userMessage if no files provided)
|
|
375
|
+
let code = "";
|
|
376
|
+
if (files.length > 0) {
|
|
377
|
+
const chunks = files.map((f) => {
|
|
378
|
+
try {
|
|
379
|
+
return `// ===== ${f} =====\n${_deps.readFileSync(f, "utf-8")}`;
|
|
380
|
+
} catch (err) {
|
|
381
|
+
return `// ===== ${f} (read error: ${err.message}) =====`;
|
|
382
|
+
}
|
|
383
|
+
});
|
|
384
|
+
code = chunks.join("\n\n");
|
|
385
|
+
} else {
|
|
386
|
+
code = userMessage;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const taskId = `cowork-debate-${Date.now()}`;
|
|
390
|
+
|
|
391
|
+
if (onProgress) {
|
|
392
|
+
onProgress({ type: "debate-started", perspectives: reviewPerspectives });
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
try {
|
|
396
|
+
const { startDebate } = await import("./cowork/debate-review-cli.js");
|
|
397
|
+
const debateResult = await startDebate({
|
|
398
|
+
target: userMessage,
|
|
399
|
+
code,
|
|
400
|
+
perspectives: reviewPerspectives,
|
|
401
|
+
llmOptions,
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
if (onProgress) {
|
|
405
|
+
onProgress({ type: "debate-completed", verdict: debateResult.verdict });
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const entry = {
|
|
409
|
+
taskId,
|
|
410
|
+
status: "completed",
|
|
411
|
+
templateId: template.id,
|
|
412
|
+
templateName: template.name,
|
|
413
|
+
mode: "debate",
|
|
414
|
+
result: {
|
|
415
|
+
summary: debateResult.summary,
|
|
416
|
+
verdict: debateResult.verdict,
|
|
417
|
+
consensusScore: debateResult.consensusScore,
|
|
418
|
+
reviews: debateResult.reviews,
|
|
419
|
+
perspectives: debateResult.perspectives,
|
|
420
|
+
artifacts: [],
|
|
421
|
+
tokenCount: 0,
|
|
422
|
+
toolsUsed: [],
|
|
423
|
+
iterationCount: debateResult.reviews.length + 1,
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
_appendHistory(cwd, entry, userMessage);
|
|
427
|
+
return entry;
|
|
428
|
+
} catch (err) {
|
|
429
|
+
const entry = {
|
|
430
|
+
taskId,
|
|
431
|
+
status: "failed",
|
|
432
|
+
templateId: template.id,
|
|
433
|
+
templateName: template.name,
|
|
434
|
+
mode: "debate",
|
|
435
|
+
result: {
|
|
436
|
+
summary: `Debate failed: ${err.message}`,
|
|
437
|
+
artifacts: [],
|
|
438
|
+
tokenCount: 0,
|
|
439
|
+
toolsUsed: [],
|
|
440
|
+
iterationCount: 0,
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
_appendHistory(cwd, entry, userMessage);
|
|
444
|
+
return entry;
|
|
131
445
|
}
|
|
132
446
|
}
|
|
133
447
|
|
|
@@ -158,6 +158,7 @@ ${ERROR_RECOVERY_PROMPT}`,
|
|
|
158
158
|
name: "数据分析",
|
|
159
159
|
category: "data",
|
|
160
160
|
acceptsFiles: true,
|
|
161
|
+
parallelStrategy: "auto",
|
|
161
162
|
fileTypes: [".csv", ".xlsx", ".xls", ".json", ".tsv", ".sqlite", ".db"],
|
|
162
163
|
systemPromptExtension: `你是数据分析专家。
|
|
163
164
|
|
|
@@ -194,6 +195,7 @@ ${ERROR_RECOVERY_PROMPT}`,
|
|
|
194
195
|
category: "research",
|
|
195
196
|
acceptsFiles: false,
|
|
196
197
|
fileTypes: [],
|
|
198
|
+
parallelStrategy: "auto",
|
|
197
199
|
shellPolicyOverrides: ["network-download"],
|
|
198
200
|
systemPromptExtension: `你是信息检索与调研专家。
|
|
199
201
|
|
|
@@ -270,6 +272,7 @@ ${ERROR_RECOVERY_PROMPT}`,
|
|
|
270
272
|
name: "代码辅助",
|
|
271
273
|
category: "development",
|
|
272
274
|
acceptsFiles: true,
|
|
275
|
+
parallelStrategy: "auto",
|
|
273
276
|
fileTypes: [
|
|
274
277
|
".js",
|
|
275
278
|
".ts",
|
|
@@ -460,6 +463,32 @@ ${OPEN_SOURCE_FIRST_PROMPT}
|
|
|
460
463
|
${FILE_HANDLING_PROMPT}
|
|
461
464
|
${ERROR_RECOVERY_PROMPT}`,
|
|
462
465
|
},
|
|
466
|
+
|
|
467
|
+
"code-review": {
|
|
468
|
+
id: "code-review",
|
|
469
|
+
name: "代码评审",
|
|
470
|
+
category: "development",
|
|
471
|
+
acceptsFiles: true,
|
|
472
|
+
fileTypes: [
|
|
473
|
+
".js",
|
|
474
|
+
".ts",
|
|
475
|
+
".py",
|
|
476
|
+
".go",
|
|
477
|
+
".rs",
|
|
478
|
+
".java",
|
|
479
|
+
".kt",
|
|
480
|
+
".cpp",
|
|
481
|
+
".c",
|
|
482
|
+
".rb",
|
|
483
|
+
".php",
|
|
484
|
+
".vue",
|
|
485
|
+
],
|
|
486
|
+
mode: "debate",
|
|
487
|
+
debatePerspectives: ["performance", "security", "maintainability"],
|
|
488
|
+
systemPromptExtension: `你是多视角代码评审的协调者。
|
|
489
|
+
将代码分发给多个专业评审员独立评审,最后综合输出裁决。
|
|
490
|
+
`,
|
|
491
|
+
},
|
|
463
492
|
};
|
|
464
493
|
|
|
465
494
|
/**
|
|
@@ -467,23 +496,49 @@ ${ERROR_RECOVERY_PROMPT}`,
|
|
|
467
496
|
* @param {string|null} templateId
|
|
468
497
|
* @returns {object} Template definition
|
|
469
498
|
*/
|
|
499
|
+
/**
|
|
500
|
+
* Extra template registry for installed user templates. The marketplace
|
|
501
|
+
* loader populates this at CLI startup via `setUserTemplates()`. Keeping
|
|
502
|
+
* it local lets `getTemplate()` / `getTemplatesForUI()` stay synchronous
|
|
503
|
+
* while still returning user-installed templates.
|
|
504
|
+
*/
|
|
505
|
+
let _userTemplates = {};
|
|
506
|
+
|
|
507
|
+
/** Called by the marketplace / CLI to register installed user templates. */
|
|
508
|
+
export function setUserTemplates(templates) {
|
|
509
|
+
_userTemplates = {};
|
|
510
|
+
if (Array.isArray(templates)) {
|
|
511
|
+
for (const tpl of templates) {
|
|
512
|
+
if (tpl?.id) _userTemplates[tpl.id] = tpl;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/** Read-only accessor for tests. */
|
|
518
|
+
export function getUserTemplates() {
|
|
519
|
+
return { ..._userTemplates };
|
|
520
|
+
}
|
|
521
|
+
|
|
470
522
|
export function getTemplate(templateId) {
|
|
471
|
-
if (
|
|
472
|
-
return
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
523
|
+
if (templateId && TASK_TEMPLATES[templateId]) {
|
|
524
|
+
return TASK_TEMPLATES[templateId];
|
|
525
|
+
}
|
|
526
|
+
if (templateId && _userTemplates[templateId]) {
|
|
527
|
+
return _userTemplates[templateId];
|
|
528
|
+
}
|
|
529
|
+
return {
|
|
530
|
+
id: "free",
|
|
531
|
+
name: "自由模式",
|
|
532
|
+
category: "general",
|
|
533
|
+
acceptsFiles: true,
|
|
534
|
+
fileTypes: [],
|
|
535
|
+
systemPromptExtension: `你是一个全能助手,可以处理用户提出的任何日常任务。
|
|
479
536
|
根据任务类型自动选择最合适的工具和方法。
|
|
480
537
|
|
|
481
538
|
${OPEN_SOURCE_FIRST_PROMPT}
|
|
482
539
|
${FILE_HANDLING_PROMPT}
|
|
483
540
|
${ERROR_RECOVERY_PROMPT}`,
|
|
484
|
-
|
|
485
|
-
}
|
|
486
|
-
return TASK_TEMPLATES[templateId];
|
|
541
|
+
};
|
|
487
542
|
}
|
|
488
543
|
|
|
489
544
|
/**
|
|
@@ -491,7 +546,7 @@ ${ERROR_RECOVERY_PROMPT}`,
|
|
|
491
546
|
* @returns {string[]}
|
|
492
547
|
*/
|
|
493
548
|
export function listTemplateIds() {
|
|
494
|
-
return Object.keys(TASK_TEMPLATES);
|
|
549
|
+
return [...Object.keys(TASK_TEMPLATES), ...Object.keys(_userTemplates)];
|
|
495
550
|
}
|
|
496
551
|
|
|
497
552
|
// ─── UI Metadata ─────────────────────────────────────────────────────────────
|
|
@@ -571,6 +626,15 @@ const UI_METADATA = {
|
|
|
571
626
|
description: "文档翻译、内容总结、论文分析",
|
|
572
627
|
examples: ["翻译 PDF 摘要", "总结长文档要点", "解释代码工作原理"],
|
|
573
628
|
},
|
|
629
|
+
"code-review": {
|
|
630
|
+
icon: "SafetyCertificateOutlined",
|
|
631
|
+
description: "多视角评审(性能 / 安全 / 可维护性),综合裁决",
|
|
632
|
+
examples: [
|
|
633
|
+
"评审这个函数的安全问题",
|
|
634
|
+
"从性能角度审查这段代码",
|
|
635
|
+
"评审 PR 的可维护性",
|
|
636
|
+
],
|
|
637
|
+
},
|
|
574
638
|
};
|
|
575
639
|
|
|
576
640
|
/**
|
|
@@ -580,8 +644,17 @@ const UI_METADATA = {
|
|
|
580
644
|
* @returns {object[]}
|
|
581
645
|
*/
|
|
582
646
|
export function getTemplatesForUI() {
|
|
583
|
-
|
|
647
|
+
const builtIn = Object.values(TASK_TEMPLATES).map((tpl) => {
|
|
584
648
|
const ui = UI_METADATA[tpl.id] || {};
|
|
649
|
+
return { tpl, ui, source: "builtin" };
|
|
650
|
+
});
|
|
651
|
+
const userInstalled = Object.values(_userTemplates).map((tpl) => ({
|
|
652
|
+
tpl,
|
|
653
|
+
// User templates carry their own ui metadata inline
|
|
654
|
+
ui: { icon: tpl.icon, description: tpl.description, examples: tpl.examples },
|
|
655
|
+
source: "user",
|
|
656
|
+
}));
|
|
657
|
+
return [...builtIn, ...userInstalled].map(({ tpl, ui, source }) => {
|
|
585
658
|
return {
|
|
586
659
|
id: tpl.id,
|
|
587
660
|
name: tpl.name,
|
|
@@ -589,10 +662,25 @@ export function getTemplatesForUI() {
|
|
|
589
662
|
category: tpl.category,
|
|
590
663
|
description: ui.description || "",
|
|
591
664
|
examples: ui.examples || [],
|
|
665
|
+
source,
|
|
592
666
|
acceptsFiles: tpl.acceptsFiles,
|
|
667
|
+
parallelStrategy: tpl.parallelStrategy || "none",
|
|
668
|
+
mode: tpl.mode || "agent",
|
|
669
|
+
...(tpl.debatePerspectives
|
|
670
|
+
? { debatePerspectives: tpl.debatePerspectives }
|
|
671
|
+
: {}),
|
|
593
672
|
...(tpl.shellPolicyOverrides
|
|
594
673
|
? { shellPolicyOverrides: tpl.shellPolicyOverrides }
|
|
595
674
|
: {}),
|
|
675
|
+
...(Array.isArray(tpl.mcpServers) && tpl.mcpServers.length > 0
|
|
676
|
+
? {
|
|
677
|
+
mcpServers: tpl.mcpServers.map((s) => ({
|
|
678
|
+
name: s.name,
|
|
679
|
+
command: s.command,
|
|
680
|
+
args: Array.isArray(s.args) ? s.args : [],
|
|
681
|
+
})),
|
|
682
|
+
}
|
|
683
|
+
: {}),
|
|
596
684
|
};
|
|
597
685
|
});
|
|
598
686
|
}
|