@agent-spaces/server 0.1.2 → 0.2.1
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/dist/adapters/claude-code-runtime/index.js +4 -1
- package/dist/adapters/git.js +2 -21
- package/dist/agents/issue-agent-runner.js +35 -21
- package/dist/agents/issue-task-controller.js +120 -73
- package/dist/agents/planner-agent.js +9 -12
- package/dist/app.js +10 -0
- package/dist/hooks/agent-hooks.js +5 -8
- package/dist/package.json +1 -1
- package/dist/routes/agent.js +40 -17
- package/dist/routes/channel.js +4 -1
- package/dist/routes/command.js +108 -0
- package/dist/routes/folder.js +44 -7
- package/dist/routes/issue.js +57 -23
- package/dist/routes/mcp.js +50 -0
- package/dist/routes/skill.js +57 -0
- package/dist/routes/subscription.js +49 -0
- package/dist/routes/task.js +16 -1
- package/dist/routes/workflow.js +63 -0
- package/dist/routes/workspace.js +2 -21
- package/dist/services/agent.js +140 -76
- package/dist/services/builtin-tools.js +72 -0
- package/dist/services/channel.js +5 -5
- package/dist/services/command-process-manager.js +136 -0
- package/dist/services/command.js +48 -0
- package/dist/services/issue.js +5 -6
- package/dist/services/mcp.js +120 -0
- package/dist/services/notification-hub/bot-commands.js +48 -16
- package/dist/services/notification-hub/helpers.js +12 -0
- package/dist/services/pty.js +10 -3
- package/dist/services/skill.js +171 -0
- package/dist/services/subscription/aicode.js +45 -0
- package/dist/services/subscription/base.js +3 -0
- package/dist/services/subscription/index.js +20 -0
- package/dist/services/subscription/minimax.js +60 -0
- package/dist/services/subscription/zhipu.js +39 -0
- package/dist/services/workflow.js +203 -0
- package/dist/services/workspace.js +0 -1
- package/dist/storage/command-store.js +17 -0
- package/dist/storage/subscription-store.js +44 -0
- package/dist/storage/workflow-store.js +40 -0
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +4 -4
- package/dist/web/__next._full.txt +22 -21
- package/dist/web/__next._head.txt +4 -4
- package/dist/web/__next._index.txt +9 -8
- package/dist/web/__next._tree.txt +2 -2
- package/dist/web/_next/static/MpJepsgfsHGGcc7rwFU8Y/_buildManifest.js +11 -0
- package/dist/web/_next/static/chunks/0-245kun-watp.js +2 -0
- package/dist/web/_next/static/chunks/0-ca_fo-yp3~z.js +1 -0
- package/dist/web/_next/static/chunks/0-vgd3j-zh3m8.js +2 -0
- package/dist/web/_next/static/chunks/0.4.g.8yf4rs0.js +3 -0
- package/dist/web/_next/static/chunks/02m_-ngl9w8co.js +1 -0
- package/dist/web/_next/static/chunks/03jbh7ud0jw~g.js +1 -0
- package/dist/web/_next/static/chunks/07kqxmubf5dua.js +1 -0
- package/dist/web/_next/static/chunks/088q-5_51dsrw.js +1 -0
- package/dist/web/_next/static/chunks/09_ki3dc5cfwv.css +1 -0
- package/dist/web/_next/static/chunks/09jryrjps0vl2.js +1 -0
- package/dist/web/_next/static/chunks/0b2tump5duj9j.js +1 -0
- package/dist/web/_next/static/chunks/0dctkv_2d2r0g.js +8 -0
- package/dist/web/_next/static/chunks/0efgv37kxyht8.js +1 -0
- package/dist/web/_next/static/chunks/0fwvdy-ml8wpk.js +1 -0
- package/dist/web/_next/static/chunks/0g4vm6.v0o_lt.js +1 -0
- package/dist/web/_next/static/chunks/0g_b4t~000.o~.js +179 -0
- package/dist/web/_next/static/chunks/0gyede80jpy3n.js +4 -0
- package/dist/web/_next/static/chunks/0h256h-tu4e0r.js +2 -0
- package/dist/web/_next/static/chunks/0ib18ul605e~a.js +1 -0
- package/dist/web/_next/static/chunks/0j1g_rd9t5ot1.js +1 -0
- package/dist/web/_next/static/chunks/0jn~llaqcxo4q.js +1 -0
- package/dist/web/_next/static/chunks/0jvmviuftg5e2.css +1 -0
- package/dist/web/_next/static/chunks/0lb8l2~6s_owo.js +1 -0
- package/dist/web/_next/static/chunks/0ni5ot2603_28.js +1 -0
- package/dist/web/_next/static/chunks/0pep4mkvt3.rh.js +31 -0
- package/dist/web/_next/static/chunks/0pq2670_ezbcj.js +1 -0
- package/dist/web/_next/static/chunks/0q_scqkk9.t53.js +2 -0
- package/dist/web/_next/static/chunks/0rrdur.v1a5r7.js +1 -0
- package/dist/web/_next/static/chunks/0spo.tmfeas-o.js +1 -0
- package/dist/web/_next/static/chunks/0tta_56qj1z8-.js +1 -0
- package/dist/web/_next/static/chunks/0u88ij9dqqh~-.js +1 -0
- package/dist/web/_next/static/chunks/0zl19l5tuoppw.js +1 -0
- package/dist/web/_next/static/chunks/11n16hogah-5..js +1 -0
- package/dist/web/_next/static/chunks/1250wo~-5dgyx.js +1 -0
- package/dist/web/_next/static/chunks/14n8i2xz4_y-e.js +1 -0
- package/dist/web/_next/static/chunks/160ji-.dfvm20.js +1 -0
- package/dist/web/_next/static/chunks/turbopack-0lxiiw.jhevml.js +1 -0
- package/dist/web/_next/static/media/favicon.0~ekuj.zhggpa.ico +0 -0
- package/dist/web/_not-found/__next._full.txt +24 -19
- package/dist/web/_not-found/__next._head.txt +4 -4
- package/dist/web/_not-found/__next._index.txt +9 -8
- package/dist/web/_not-found/__next._not-found.__PAGE__.txt +2 -2
- package/dist/web/_not-found/__next._not-found.txt +3 -3
- package/dist/web/_not-found/__next._tree.txt +2 -2
- package/dist/web/_not-found.html +1 -1
- package/dist/web/_not-found.txt +24 -19
- package/dist/web/apple-touch-icon.png +0 -0
- package/dist/web/favicon.ico +0 -0
- package/dist/web/icon-192.png +0 -0
- package/dist/web/icon-512.png +0 -0
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +22 -21
- package/dist/web/login/__next._full.txt +24 -23
- package/dist/web/login/__next._head.txt +4 -4
- package/dist/web/login/__next._index.txt +9 -8
- package/dist/web/login/__next._tree.txt +2 -2
- package/dist/web/login/__next.login.__PAGE__.txt +4 -4
- package/dist/web/login/__next.login.txt +3 -3
- package/dist/web/login.html +1 -1
- package/dist/web/login.txt +24 -23
- package/dist/web/settings/__next._full.txt +34 -0
- package/dist/web/settings/__next._head.txt +6 -0
- package/dist/web/settings/__next._index.txt +11 -0
- package/dist/web/settings/__next._tree.txt +8 -0
- package/dist/web/settings/__next.settings.__PAGE__.txt +9 -0
- package/dist/web/settings/__next.settings.txt +7 -0
- package/dist/web/settings/agents/__next._full.txt +38 -0
- package/dist/web/settings/agents/__next._head.txt +6 -0
- package/dist/web/settings/agents/__next._index.txt +11 -0
- package/dist/web/settings/agents/__next._tree.txt +8 -0
- package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +9 -0
- package/dist/web/settings/agents/__next.settings.agents.txt +5 -0
- package/dist/web/settings/agents/__next.settings.txt +7 -0
- package/dist/web/settings/agents.html +1 -0
- package/dist/web/settings/agents.txt +38 -0
- package/dist/web/settings/mcps/__next._full.txt +38 -0
- package/dist/web/settings/mcps/__next._head.txt +6 -0
- package/dist/web/settings/mcps/__next._index.txt +11 -0
- package/dist/web/settings/mcps/__next._tree.txt +8 -0
- package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +9 -0
- package/dist/web/settings/mcps/__next.settings.mcps.txt +5 -0
- package/dist/web/settings/mcps/__next.settings.txt +7 -0
- package/dist/web/settings/mcps.html +1 -0
- package/dist/web/settings/mcps.txt +38 -0
- package/dist/web/settings/models/__next._full.txt +38 -0
- package/dist/web/settings/models/__next._head.txt +6 -0
- package/dist/web/settings/models/__next._index.txt +11 -0
- package/dist/web/settings/models/__next._tree.txt +8 -0
- package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +9 -0
- package/dist/web/settings/models/__next.settings.models.txt +5 -0
- package/dist/web/settings/models/__next.settings.txt +7 -0
- package/dist/web/settings/models.html +1 -0
- package/dist/web/settings/models.txt +38 -0
- package/dist/web/settings/providers/__next._full.txt +38 -0
- package/dist/web/settings/providers/__next._head.txt +6 -0
- package/dist/web/settings/providers/__next._index.txt +11 -0
- package/dist/web/settings/providers/__next._tree.txt +8 -0
- package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +9 -0
- package/dist/web/settings/providers/__next.settings.providers.txt +5 -0
- package/dist/web/settings/providers/__next.settings.txt +7 -0
- package/dist/web/settings/providers.html +1 -0
- package/dist/web/settings/providers.txt +38 -0
- package/dist/web/settings/skills/__next._full.txt +38 -0
- package/dist/web/settings/skills/__next._head.txt +6 -0
- package/dist/web/settings/skills/__next._index.txt +11 -0
- package/dist/web/settings/skills/__next._tree.txt +8 -0
- package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +9 -0
- package/dist/web/settings/skills/__next.settings.skills.txt +5 -0
- package/dist/web/settings/skills/__next.settings.txt +7 -0
- package/dist/web/settings/skills.html +1 -0
- package/dist/web/settings/skills.txt +38 -0
- package/dist/web/settings.html +1 -0
- package/dist/web/settings.txt +34 -0
- package/dist/web/workflows/__next._full.txt +35 -0
- package/dist/web/workflows/__next._head.txt +6 -0
- package/dist/web/workflows/__next._index.txt +11 -0
- package/dist/web/workflows/__next._tree.txt +9 -0
- package/dist/web/workflows/__next.workflows.__PAGE__.txt +10 -0
- package/dist/web/workflows/__next.workflows.txt +5 -0
- package/dist/web/workflows.html +1 -0
- package/dist/web/workflows.txt +35 -0
- package/dist/web/workspace/_/__next._full.txt +25 -20
- package/dist/web/workspace/_/__next._head.txt +4 -4
- package/dist/web/workspace/_/__next._index.txt +9 -8
- package/dist/web/workspace/_/__next._tree.txt +2 -2
- package/dist/web/workspace/_/__next.workspace.$d$id.__PAGE__.txt +3 -3
- package/dist/web/workspace/_/__next.workspace.$d$id.txt +3 -3
- package/dist/web/workspace/_/__next.workspace.txt +3 -3
- package/dist/web/workspace/_.html +1 -1
- package/dist/web/workspace/_.txt +25 -20
- package/dist/web/workspaces/__next._full.txt +24 -23
- package/dist/web/workspaces/__next._head.txt +4 -4
- package/dist/web/workspaces/__next._index.txt +9 -8
- package/dist/web/workspaces/__next._tree.txt +2 -2
- package/dist/web/workspaces/__next.workspaces.__PAGE__.txt +4 -4
- package/dist/web/workspaces/__next.workspaces.txt +3 -3
- package/dist/web/workspaces.html +1 -1
- package/dist/web/workspaces.txt +24 -23
- package/dist/ws/agent-prompt.js +84 -0
- package/dist/ws/agent-runner.js +592 -0
- package/dist/ws/handler.js +9 -1200
- package/dist/ws/html-utils.js +30 -0
- package/dist/ws/message-parts.js +498 -0
- package/package.json +3 -2
- package/dist/web/_next/static/chunks/038whpa0zpnas.js +0 -1
- package/dist/web/_next/static/chunks/06q5go~xoz5a3.js +0 -1
- package/dist/web/_next/static/chunks/095.wizobwtyg.js +0 -2
- package/dist/web/_next/static/chunks/0bfg.w~u-83h5.js +0 -1
- package/dist/web/_next/static/chunks/0ce7i6~sb20rv.js +0 -113
- package/dist/web/_next/static/chunks/0d4~pcva1uk-a.js +0 -1
- package/dist/web/_next/static/chunks/0iq70n_u75nyu.js +0 -1
- package/dist/web/_next/static/chunks/0memz-8zsbxpu.js +0 -1
- package/dist/web/_next/static/chunks/0nw~w.3~twebx.js +0 -2
- package/dist/web/_next/static/chunks/0pyytgz~5vt0f.js +0 -31
- package/dist/web/_next/static/chunks/0ujjcrz~1nq.q.css +0 -1
- package/dist/web/_next/static/chunks/0vdnx9n41dyjl.js +0 -1
- package/dist/web/_next/static/chunks/0yl4mqmxtll6g.js +0 -1
- package/dist/web/_next/static/chunks/0zcbfka5tcle3.js +0 -1
- package/dist/web/_next/static/chunks/0~eo58u99i.fr.js +0 -8
- package/dist/web/_next/static/chunks/13_2vxyccsv84.js +0 -4
- package/dist/web/_next/static/chunks/13wfs~urgxu0w.js +0 -1
- package/dist/web/_next/static/chunks/157~3c6wqkt83.js +0 -1
- package/dist/web/_next/static/chunks/15jvow_z4uq-..js +0 -1
- package/dist/web/_next/static/chunks/15v697nf~r-cy.js +0 -2
- package/dist/web/_next/static/chunks/turbopack-164~7ulq9o9yc.js +0 -1
- package/dist/web/_next/static/media/favicon.0x3dzn~oxb6tn.ico +0 -0
- package/dist/web/_next/static/owMnKmxATbtXK_J_k_uHh/_buildManifest.js +0 -21
- /package/dist/web/_next/static/{owMnKmxATbtXK_J_k_uHh → MpJepsgfsHGGcc7rwFU8Y}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{owMnKmxATbtXK_J_k_uHh → MpJepsgfsHGGcc7rwFU8Y}/_ssgManifest.js +0 -0
|
@@ -31,8 +31,11 @@ export class ClaudeCodeRuntime {
|
|
|
31
31
|
const apiKey = this.adapterRun ? 'default' : this.config.apiKey;
|
|
32
32
|
const model = getClaudeCodeModel(this.config);
|
|
33
33
|
const additionalDirectories = normalizeAdditionalDirectories(cwd, options?.sandboxDirs);
|
|
34
|
+
const sdkMcpServers = normalizeMcpServers(options?.mcpServers, options?.functionTools);
|
|
35
|
+
const sdkMcpServerNames = Object.keys(sdkMcpServers ?? {});
|
|
34
36
|
d(`starting | cwd=${cwd} model=${model ?? 'default'} targetModel=${this.config.model ?? 'default'} provider=${this.config.provider ?? 'default'} baseURL=${baseURL ?? 'default'} permissionMode=${permissionMode} maxTurns=${options?.maxTurns ?? '∞'} tools=claude_code mcpServers=${Object.keys(options?.mcpServers ?? {}).join(',') || '-'} skills=${skillNames.join(',') || '-'} configDir=${configDir ?? 'default'} sandboxDirs=${additionalDirectories.join(',') || '-'} claudeExecutable=${claudeExecutable ?? 'sdk-default'}`);
|
|
35
37
|
d(`prompt: ${prompt.slice(0, 300)}${prompt.length > 300 ? '...' : ''}`);
|
|
38
|
+
d(`sdk mcp servers | ${sdkMcpServerNames.join(',') || '-'}`);
|
|
36
39
|
try {
|
|
37
40
|
const queryOptions = {
|
|
38
41
|
cwd,
|
|
@@ -40,7 +43,7 @@ export class ClaudeCodeRuntime {
|
|
|
40
43
|
maxTurns: options?.maxTurns,
|
|
41
44
|
pathToClaudeCodeExecutable: claudeExecutable,
|
|
42
45
|
tools: { type: 'preset', preset: 'claude_code' },
|
|
43
|
-
mcpServers:
|
|
46
|
+
mcpServers: sdkMcpServers,
|
|
44
47
|
skills: skillNames,
|
|
45
48
|
managedSettings: {
|
|
46
49
|
strictPluginOnlyCustomization: ['mcp'],
|
package/dist/adapters/git.js
CHANGED
|
@@ -18,18 +18,6 @@ function getGit(workspace) {
|
|
|
18
18
|
if (existing)
|
|
19
19
|
return existing;
|
|
20
20
|
const git = simpleGit(workspace.boundDirs[0], getGitOptions());
|
|
21
|
-
git.outputHandler((_binary, stdout, stderr) => {
|
|
22
|
-
stderr.on('data', (chunk) => {
|
|
23
|
-
const text = chunk.toString().trim();
|
|
24
|
-
if (text)
|
|
25
|
-
console.log(`[git:${workspace.id}] ${text}`);
|
|
26
|
-
});
|
|
27
|
-
stdout.on('data', (chunk) => {
|
|
28
|
-
const text = chunk.toString().trim();
|
|
29
|
-
if (text)
|
|
30
|
-
console.log(`[git:${workspace.id}] ${text}`);
|
|
31
|
-
});
|
|
32
|
-
});
|
|
33
21
|
gitInstances.set(workspace.id, git);
|
|
34
22
|
return git;
|
|
35
23
|
}
|
|
@@ -288,19 +276,12 @@ export async function gitClone(targetDir, url, onProgress) {
|
|
|
288
276
|
throw new Error(`目录 ${cloneDir} 已存在`);
|
|
289
277
|
}
|
|
290
278
|
const git = simpleGit(getGitOptions());
|
|
291
|
-
git.outputHandler((_binary,
|
|
279
|
+
git.outputHandler((_binary, _stdout, stderr) => {
|
|
292
280
|
stderr.on('data', (chunk) => {
|
|
293
|
-
const
|
|
294
|
-
console.log(`[git:clone] ${text.trim()}`);
|
|
295
|
-
const parsed = parseCloneProgress(text);
|
|
281
|
+
const parsed = parseCloneProgress(chunk.toString());
|
|
296
282
|
if (parsed)
|
|
297
283
|
onProgress(parsed);
|
|
298
284
|
});
|
|
299
|
-
stdout.on('data', (chunk) => {
|
|
300
|
-
const text = chunk.toString().trim();
|
|
301
|
-
if (text)
|
|
302
|
-
console.log(`[git:clone] ${text}`);
|
|
303
|
-
});
|
|
304
285
|
});
|
|
305
286
|
await git.clone(url, cloneDir, ['--progress']);
|
|
306
287
|
return cloneDir;
|
|
@@ -1,38 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { syncIssueTasksAfterPlanning } from './issue-task-controller.js';
|
|
1
|
+
import { scheduleRunnableIssueTasks, createTasksFromWorkflow } from './issue-task-controller.js';
|
|
3
2
|
import * as issueService from '../services/issue.js';
|
|
4
|
-
import * as issueCommentService from '../services/issue-comment.js';
|
|
5
3
|
import * as taskService from '../services/task.js';
|
|
6
4
|
import * as agentService from '../services/agent.js';
|
|
7
|
-
|
|
5
|
+
import * as workflowService from '../services/workflow.js';
|
|
6
|
+
export async function runIssueAutomation(workspaceId, issueId, ctx) {
|
|
8
7
|
const issue = issueService.getById(workspaceId, issueId);
|
|
9
8
|
if (!issue) {
|
|
10
9
|
console.warn(`[issue-runner] issue not found workspaceId=${workspaceId} issueId=${issueId}`);
|
|
11
10
|
return;
|
|
12
11
|
}
|
|
12
|
+
// Workflow template branch
|
|
13
|
+
if (issue.workflowId) {
|
|
14
|
+
const template = workflowService.getWorkflow(issue.workflowId);
|
|
15
|
+
if (template) {
|
|
16
|
+
try {
|
|
17
|
+
createTasksFromWorkflow(workspaceId, issueId, template, ctx);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
catch (err) {
|
|
21
|
+
console.warn(`Workflow execution failed for issue ${issueId}: ${err.message}.`);
|
|
22
|
+
markIssueError(workspaceId, issueId, `Workflow execution failed: ${err.message}`, ctx);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
console.warn(`Workflow template ${issue.workflowId} not found`);
|
|
28
|
+
markIssueError(workspaceId, issueId, `Workflow template ${issue.workflowId} not found`, ctx);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
13
32
|
const tasks = taskService.list(workspaceId, issueId);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
await runPlanner(workspaceId, issueId, ctx);
|
|
33
|
+
if (tasks.length > 0) {
|
|
34
|
+
await scheduleRunnableIssueTasks(workspaceId, issueId, ctx);
|
|
17
35
|
return;
|
|
18
36
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
planOutput: [],
|
|
22
|
-
}, ctx);
|
|
23
|
-
}
|
|
24
|
-
export function shouldForcePlannerFromMentions(workspaceId, mentions) {
|
|
25
|
-
const mentionedIds = new Set(mentions);
|
|
26
|
-
return (agentService.listPresets(workspaceId) ?? []).some((agent) => mentionedIds.has(agent.id) && agent.role === 'planner' && agent.enabled !== false);
|
|
37
|
+
console.warn(`[issue-runner] no workflow configured for issue workspaceId=${workspaceId} issueId=${issueId}`);
|
|
38
|
+
markIssueError(workspaceId, issueId, 'No workflow configured for issue', ctx);
|
|
27
39
|
}
|
|
28
40
|
export function hasActiveIssueAutomation(workspaceId) {
|
|
29
41
|
return agentService.list(workspaceId).some((session) => session.status === 'active' &&
|
|
30
|
-
['
|
|
42
|
+
!['scheduler', 'bot'].includes(session.role));
|
|
31
43
|
}
|
|
32
|
-
function
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
function markIssueError(workspaceId, issueId, message, ctx) {
|
|
45
|
+
const issue = issueService.getById(workspaceId, issueId);
|
|
46
|
+
const updated = issueService.markError(workspaceId, issueId, message);
|
|
47
|
+
if (!updated)
|
|
48
|
+
return;
|
|
49
|
+
ctx.broadcast('issue.status_changed', { issueId, from: issue?.status ?? 'draft', to: 'error' });
|
|
50
|
+
ctx.broadcast('issue.updated', updated);
|
|
37
51
|
}
|
|
38
52
|
//# sourceMappingURL=issue-agent-runner.js.map
|
|
@@ -3,7 +3,8 @@ import * as agentService from '../services/agent.js';
|
|
|
3
3
|
import * as channelService from '../services/channel.js';
|
|
4
4
|
import * as issueService from '../services/issue.js';
|
|
5
5
|
import * as taskService from '../services/task.js';
|
|
6
|
-
import
|
|
6
|
+
import * as workspaceService from '../services/workspace.js';
|
|
7
|
+
import { mapWorkflowToTaskDrafts, validateWorkflowForRun } from '../services/workflow.js';
|
|
7
8
|
import { createIssueFunctionTools } from '../services/builtin-tools.js';
|
|
8
9
|
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
9
10
|
import { completeIssueAgentProgress, createIssueAgentProgress, createIssueAgentProgressTracker } from './issue-agent-progress.js';
|
|
@@ -14,9 +15,9 @@ export async function syncIssueTasksAfterPlanning(workspaceId, issueId, input, c
|
|
|
14
15
|
console.warn(`[issue-task-controller] issue not found workspaceId=${workspaceId} issueId=${issueId}`);
|
|
15
16
|
return;
|
|
16
17
|
}
|
|
17
|
-
const taskSyncPreset =
|
|
18
|
+
const taskSyncPreset = findTaskSyncAgentForIssue(workspaceId, issue, input.plannerPreset);
|
|
18
19
|
if (!taskSyncPreset) {
|
|
19
|
-
console.warn(`[issue-task-controller] no task
|
|
20
|
+
console.warn(`[issue-task-controller] no task sync agent member found workspaceId=${workspaceId} issueId=${issueId}`);
|
|
20
21
|
updateIssueStatus(workspaceId, issueId, 'error', ctx);
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
@@ -28,7 +29,7 @@ export async function syncIssueTasksAfterPlanning(workspaceId, issueId, input, c
|
|
|
28
29
|
ctx.broadcast('agent.status_changed', { agentId: taskSyncAgent.id, from: fromStatus, to: 'active' });
|
|
29
30
|
ctx.broadcast('agent.output', { agentId: taskSyncAgent.id, data: `Syncing issue tasks: ${issueId}` });
|
|
30
31
|
const startTime = Date.now();
|
|
31
|
-
const taskSyncWorkingDir =
|
|
32
|
+
const taskSyncWorkingDir = resolveIssueWorkspaceRoot(workspaceId);
|
|
32
33
|
const progress = createIssueAgentProgress(workspaceId, issue, taskSyncPreset, taskSyncAgent.id, {
|
|
33
34
|
runtime: taskSyncPreset.runtimeKind,
|
|
34
35
|
model: taskSyncPreset.modelId,
|
|
@@ -122,13 +123,16 @@ export async function runIssueTask(workspaceId, issueId, taskId, ctx) {
|
|
|
122
123
|
console.warn(`[issue-task-controller] missing issue/task workspaceId=${workspaceId} issueId=${issueId} taskId=${taskId}`);
|
|
123
124
|
return;
|
|
124
125
|
}
|
|
125
|
-
|
|
126
|
-
|
|
126
|
+
if (task.status !== 'pending') {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const taskAgentPreset = findAgentForTask(workspaceId, issue, task);
|
|
130
|
+
if (!taskAgentPreset) {
|
|
127
131
|
const missingExecutorResult = {
|
|
128
132
|
success: false,
|
|
129
|
-
summary: 'No
|
|
133
|
+
summary: 'No runnable agent configured in issue channel members',
|
|
130
134
|
artifacts: [],
|
|
131
|
-
error: 'No
|
|
135
|
+
error: 'No runnable agent member found for issue channel',
|
|
132
136
|
};
|
|
133
137
|
const failed = taskService.updateStatus(workspaceId, taskId, 'failed', {
|
|
134
138
|
result: {
|
|
@@ -142,69 +146,69 @@ export async function runIssueTask(workspaceId, issueId, taskId, ctx) {
|
|
|
142
146
|
await handleTaskFailure(workspaceId, issueId, taskId, missingExecutorResult, ctx);
|
|
143
147
|
return;
|
|
144
148
|
}
|
|
145
|
-
const
|
|
146
|
-
ctx.broadcast('agent.started',
|
|
147
|
-
const
|
|
148
|
-
agentService.updateStatus(workspaceId,
|
|
149
|
-
issueService.addAgent(workspaceId, issueId,
|
|
150
|
-
ctx.broadcast('agent.status_changed', { agentId:
|
|
151
|
-
const runningTask = taskService.assignAgent(workspaceId, taskId,
|
|
149
|
+
const taskAgent = agentService.getOrCreateSessionForConfig(workspaceId, taskAgentPreset);
|
|
150
|
+
ctx.broadcast('agent.started', taskAgent);
|
|
151
|
+
const agentFromStatus = taskAgent.status;
|
|
152
|
+
agentService.updateStatus(workspaceId, taskAgent.id, 'active');
|
|
153
|
+
issueService.addAgent(workspaceId, issueId, taskAgentPreset.id);
|
|
154
|
+
ctx.broadcast('agent.status_changed', { agentId: taskAgent.id, from: agentFromStatus, to: 'active' });
|
|
155
|
+
const runningTask = taskService.assignAgent(workspaceId, taskId, taskAgent.id);
|
|
152
156
|
if (!runningTask) {
|
|
153
|
-
agentService.complete(workspaceId,
|
|
157
|
+
agentService.complete(workspaceId, taskAgent.id, 'Task not found');
|
|
154
158
|
return;
|
|
155
159
|
}
|
|
156
160
|
broadcastTaskUpdate(ctx, runningTask, task.status);
|
|
157
|
-
agentService.assignTask(workspaceId,
|
|
158
|
-
const runtime = createRuntimeForPreset(
|
|
159
|
-
const
|
|
161
|
+
agentService.assignTask(workspaceId, taskAgent.id, taskId);
|
|
162
|
+
const runtime = createRuntimeForPreset(taskAgentPreset);
|
|
163
|
+
const agentWorkingDir = resolveIssueWorkspaceRoot(workspaceId);
|
|
160
164
|
const startTime = Date.now();
|
|
161
|
-
const progress = createIssueAgentProgress(workspaceId, issue,
|
|
162
|
-
runtime:
|
|
163
|
-
model:
|
|
165
|
+
const progress = createIssueAgentProgress(workspaceId, issue, taskAgentPreset, taskAgent.id, {
|
|
166
|
+
runtime: taskAgentPreset.runtimeKind,
|
|
167
|
+
model: taskAgentPreset.modelId,
|
|
164
168
|
taskId,
|
|
165
|
-
phase:
|
|
169
|
+
phase: taskAgentPreset.role,
|
|
166
170
|
});
|
|
167
|
-
const
|
|
171
|
+
const agentTracker = createIssueAgentProgressTracker({
|
|
168
172
|
workspaceId,
|
|
169
173
|
issue,
|
|
170
174
|
progress,
|
|
171
|
-
agentSessionId:
|
|
172
|
-
workspaceRoot:
|
|
175
|
+
agentSessionId: taskAgent.id,
|
|
176
|
+
workspaceRoot: agentWorkingDir,
|
|
173
177
|
onOutput: (line) => {
|
|
174
|
-
ctx.broadcast('agent.output', { agentId:
|
|
178
|
+
ctx.broadcast('agent.output', { agentId: taskAgent.id, data: line });
|
|
175
179
|
ctx.broadcast('task.output', { taskId, data: line });
|
|
176
180
|
},
|
|
177
181
|
});
|
|
178
|
-
ctx.broadcast('agent.output', { agentId:
|
|
182
|
+
ctx.broadcast('agent.output', { agentId: taskAgent.id, data: `Executing task: ${runningTask.title}` });
|
|
179
183
|
ctx.broadcast('agent.output', {
|
|
180
|
-
agentId:
|
|
181
|
-
data: `[debug]
|
|
184
|
+
agentId: taskAgent.id,
|
|
185
|
+
data: `[debug] workflow agentConfigId=${taskAgentPreset.id} role=${taskAgentPreset.role} taskAgentConfigId=${runningTask.agentConfigId || '(fallback)'} runtime=${taskAgentPreset.runtimeKind ?? 'open-agent-sdk'}`,
|
|
182
186
|
});
|
|
183
|
-
const result = await runtime.execute(
|
|
187
|
+
const result = await runtime.execute(buildTaskAgentPrompt(issue, runningTask, taskAgentPreset, agentWorkingDir), agentWorkingDir, {
|
|
184
188
|
maxTurns: 100,
|
|
185
|
-
mcpServers: agentService.getMcpServers(
|
|
186
|
-
functionTools: createCurrentIssueTools(workspaceId, issue,
|
|
187
|
-
skills: agentService.getAvailableSkillNames(agentService.getAgentConfigDir(workspaceId,
|
|
188
|
-
configDir: agentService.getAgentConfigDir(workspaceId,
|
|
189
|
-
sandboxDirs: runningTask.sandboxDirs ??
|
|
190
|
-
onEvent:
|
|
189
|
+
mcpServers: agentService.getMcpServers(taskAgentPreset.mcps),
|
|
190
|
+
functionTools: createCurrentIssueTools(workspaceId, issue, taskAgentPreset),
|
|
191
|
+
skills: agentService.getAvailableSkillNames(agentService.getAgentConfigDir(workspaceId, taskAgentPreset), taskAgentPreset.skills),
|
|
192
|
+
configDir: agentService.getAgentConfigDir(workspaceId, taskAgentPreset),
|
|
193
|
+
sandboxDirs: runningTask.sandboxDirs ?? taskAgentPreset.sandboxDirs,
|
|
194
|
+
onEvent: agentTracker.handleEvent,
|
|
191
195
|
});
|
|
192
|
-
if (
|
|
196
|
+
if (agentTracker.output.length === 0) {
|
|
193
197
|
for (const line of result.output) {
|
|
194
|
-
|
|
195
|
-
ctx.broadcast('agent.output', { agentId:
|
|
198
|
+
agentTracker.output.push(line);
|
|
199
|
+
ctx.broadcast('agent.output', { agentId: taskAgent.id, data: line });
|
|
196
200
|
ctx.broadcast('task.output', { taskId, data: line });
|
|
197
201
|
}
|
|
198
202
|
}
|
|
199
|
-
completeIssueAgentProgress(workspaceId, issue, progress, result.summary,
|
|
200
|
-
runtime:
|
|
201
|
-
model:
|
|
203
|
+
completeIssueAgentProgress(workspaceId, issue, progress, result.summary, agentTracker.output, {
|
|
204
|
+
runtime: taskAgentPreset.runtimeKind,
|
|
205
|
+
model: taskAgentPreset.modelId,
|
|
202
206
|
duration: Date.now() - startTime,
|
|
203
207
|
messageStatus: result.success ? 'completed' : 'error',
|
|
204
|
-
parts:
|
|
205
|
-
sessionId:
|
|
206
|
-
workspaceRoot:
|
|
207
|
-
model:
|
|
208
|
+
parts: agentTracker.buildParts({
|
|
209
|
+
sessionId: taskAgent.id,
|
|
210
|
+
workspaceRoot: agentWorkingDir,
|
|
211
|
+
model: taskAgentPreset.modelId,
|
|
208
212
|
usage: result.usage,
|
|
209
213
|
success: result.success,
|
|
210
214
|
error: result.error,
|
|
@@ -214,21 +218,22 @@ export async function runIssueTask(workspaceId, issueId, taskId, ctx) {
|
|
|
214
218
|
const failedTask = taskService.updateStatus(workspaceId, taskId, 'failed', { result });
|
|
215
219
|
broadcastTaskUpdate(ctx, failedTask, 'running');
|
|
216
220
|
}
|
|
217
|
-
agentService.complete(workspaceId,
|
|
218
|
-
runtime:
|
|
219
|
-
model:
|
|
221
|
+
agentService.complete(workspaceId, taskAgent.id, result.success ? undefined : result.error || result.summary, {
|
|
222
|
+
runtime: taskAgentPreset.runtimeKind,
|
|
223
|
+
model: taskAgentPreset.modelId,
|
|
220
224
|
summary: result.summary,
|
|
221
|
-
output:
|
|
225
|
+
output: agentTracker.output.length ? agentTracker.output : result.output,
|
|
222
226
|
durationMs: Date.now() - startTime,
|
|
223
227
|
usage: result.usage,
|
|
224
228
|
costUsd: result.costUsd,
|
|
225
229
|
});
|
|
226
|
-
ctx.broadcast('agent.completed', { agentId:
|
|
230
|
+
ctx.broadcast('agent.completed', { agentId: taskAgent.id, result });
|
|
227
231
|
if (!result.success) {
|
|
228
232
|
await handleTaskFailure(workspaceId, issueId, taskId, result, ctx);
|
|
229
233
|
return;
|
|
230
234
|
}
|
|
231
|
-
|
|
235
|
+
const completedTask = taskService.complete(workspaceId, taskId, result);
|
|
236
|
+
broadcastTaskUpdate(ctx, completedTask, 'running');
|
|
232
237
|
await scheduleRunnableIssueTasks(workspaceId, issueId, ctx);
|
|
233
238
|
}
|
|
234
239
|
export async function continueIssueTaskScheduling(workspaceId, issueId, ctx) {
|
|
@@ -274,7 +279,7 @@ function createTaskSyncTools(workspaceId, issue, preset, ctx) {
|
|
|
274
279
|
},
|
|
275
280
|
];
|
|
276
281
|
}
|
|
277
|
-
function replaceIssueTasksFromDrafts(workspaceId, issueId, ctx, drafts) {
|
|
282
|
+
export function replaceIssueTasksFromDrafts(workspaceId, issueId, ctx, drafts) {
|
|
278
283
|
const issue = requireIssue(workspaceId, issueId);
|
|
279
284
|
const validAgentIds = new Set(getIssueMemberPresets(workspaceId, issue).map((agent) => agent.id));
|
|
280
285
|
const normalizedDrafts = drafts.map((task) => ({
|
|
@@ -307,25 +312,62 @@ function replaceIssueTasksFromDrafts(workspaceId, issueId, ctx, drafts) {
|
|
|
307
312
|
ctx.broadcast('issue.updated', issueTasks);
|
|
308
313
|
return updated;
|
|
309
314
|
}
|
|
310
|
-
function
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
315
|
+
export function createTasksFromWorkflow(workspaceId, issueId, template, ctx) {
|
|
316
|
+
const issue = requireIssue(workspaceId, issueId);
|
|
317
|
+
ensureWorkflowAgentsForRun(workspaceId, issue, template, ctx);
|
|
318
|
+
// Validate all agents exist, are enabled, and are in channel members
|
|
319
|
+
const channel = channelService.getChannel(workspaceId, issue.channelId);
|
|
320
|
+
const memberAgentIds = new Set(channel?.members ?? []);
|
|
321
|
+
const validationError = validateWorkflowForRun(workspaceId, template, memberAgentIds);
|
|
322
|
+
if (validationError) {
|
|
323
|
+
throw new Error(`Workflow validation failed: ${validationError}`);
|
|
316
324
|
}
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
325
|
+
const drafts = mapWorkflowToTaskDrafts(template);
|
|
326
|
+
issueService.updateStatus(workspaceId, issueId, 'planned');
|
|
327
|
+
ctx.broadcast('issue.status_changed', { issueId, oldStatus: issue.status, newStatus: 'planned' });
|
|
328
|
+
replaceIssueTasksFromDrafts(workspaceId, issueId, ctx, drafts);
|
|
329
|
+
issueService.updateStatus(workspaceId, issueId, 'in_progress');
|
|
330
|
+
ctx.broadcast('issue.status_changed', { issueId, oldStatus: 'planned', newStatus: 'in_progress' });
|
|
331
|
+
ctx.broadcast('issue.updated', issueService.getById(workspaceId, issueId));
|
|
332
|
+
scheduleRunnableIssueTasks(workspaceId, issueId, ctx).catch((err) => {
|
|
333
|
+
console.error(`[workflow] task scheduling failed for issue ${issueId}:`, err);
|
|
334
|
+
});
|
|
323
335
|
}
|
|
324
|
-
function
|
|
336
|
+
function ensureWorkflowAgentsForRun(workspaceId, issue, template, ctx) {
|
|
337
|
+
const workflowAgentIds = [...new Set(template.nodes.map((node) => node.data.agentConfigId).filter(Boolean))];
|
|
338
|
+
const mergedMembers = [...new Set([...(issue.members ?? []), ...workflowAgentIds])];
|
|
339
|
+
const membersChanged = mergedMembers.length !== (issue.members ?? []).length
|
|
340
|
+
|| mergedMembers.some((member, index) => member !== issue.members?.[index]);
|
|
341
|
+
if (membersChanged) {
|
|
342
|
+
issue.members = mergedMembers;
|
|
343
|
+
const savedIssue = issueService.save(workspaceId, issue);
|
|
344
|
+
ctx.broadcast('issue.updated', savedIssue);
|
|
345
|
+
}
|
|
325
346
|
const channel = channelService.getChannel(workspaceId, issue.channelId);
|
|
326
|
-
|
|
347
|
+
const mergedChannelMembers = [...new Set([...(channel?.members ?? []), ...workflowAgentIds])];
|
|
348
|
+
const channelMembersChanged = mergedChannelMembers.length !== (channel?.members ?? []).length
|
|
349
|
+
|| mergedChannelMembers.some((member, index) => member !== channel?.members?.[index]);
|
|
350
|
+
if (channelMembersChanged) {
|
|
351
|
+
const updatedChannel = channelService.updateChannel(workspaceId, issue.channelId, { members: mergedChannelMembers });
|
|
352
|
+
if (updatedChannel)
|
|
353
|
+
ctx.broadcast('channel.updated', updatedChannel);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
function findAgentForTask(workspaceId, issue, task) {
|
|
357
|
+
const assignable = getIssueMemberPresets(workspaceId, issue);
|
|
358
|
+
if (!task.agentConfigId)
|
|
327
359
|
return null;
|
|
328
|
-
return
|
|
360
|
+
return assignable.find((agent) => agent.id === task.agentConfigId) ?? null;
|
|
361
|
+
}
|
|
362
|
+
function findTaskSyncAgentForIssue(workspaceId, issue, plannerPreset) {
|
|
363
|
+
const assignable = getIssueMemberPresets(workspaceId, issue);
|
|
364
|
+
const findByRole = (role) => assignable.find((agent) => agent.role === role) ?? null;
|
|
365
|
+
return plannerPreset
|
|
366
|
+
?? findByRole('task_creator')
|
|
367
|
+
?? findByRole('agent')
|
|
368
|
+
?? findByRole('custom')
|
|
369
|
+
?? findByRole('executor')
|
|
370
|
+
?? assignable.find((agent) => !['scheduler', 'bot'].includes(agent.role)) ?? null;
|
|
329
371
|
}
|
|
330
372
|
function getIssueMemberPresets(workspaceId, issue) {
|
|
331
373
|
const channel = channelService.getChannel(workspaceId, issue.channelId);
|
|
@@ -390,6 +432,9 @@ function createRuntimeForPreset(preset) {
|
|
|
390
432
|
...getThinkingRuntimeConfig(preset),
|
|
391
433
|
});
|
|
392
434
|
}
|
|
435
|
+
function resolveIssueWorkspaceRoot(workspaceId) {
|
|
436
|
+
return workspaceService.getById(workspaceId)?.boundDirs?.[0] || process.cwd();
|
|
437
|
+
}
|
|
393
438
|
function buildTaskSyncPrompt(issue, input, workingDir) {
|
|
394
439
|
return [
|
|
395
440
|
'You are the issue task synchronization controller.',
|
|
@@ -400,9 +445,9 @@ function buildTaskSyncPrompt(issue, input, workingDir) {
|
|
|
400
445
|
'Use ReplaceIssueTasks to write tasks. Do not rely on private planner-only context.',
|
|
401
446
|
'Create coarse-grained, independently deliverable tasks. Default to a single implementation task for one cohesive issue.',
|
|
402
447
|
'NEVER create review/audit/审查 tasks. The review phase is handled automatically by the system after all implementation tasks complete — do not include it as a task.',
|
|
403
|
-
'Split into multiple tasks only when the issue clearly requires major cross-area work, such as separate frontend and backend changes, database/API contract changes plus UI changes, or independent workstreams that different
|
|
448
|
+
'Split into multiple tasks only when the issue clearly requires major cross-area work, such as separate frontend and backend changes, database/API contract changes plus UI changes, or independent workstreams that different agents can complete without stepping on each other.',
|
|
404
449
|
'Do not split by tiny implementation steps such as "update types", "add route", "adjust UI text", "run tests", or "write docs" unless that item is itself a substantial deliverable.',
|
|
405
|
-
'Each task description should include the relevant implementation scope and expected verification, so
|
|
450
|
+
'Each task description should include the relevant implementation scope and expected verification, so agents do not need a separate task for every small step.',
|
|
406
451
|
'Assign only valid agentConfigId values from ViewCurrentChannelIssue.validAgentConfigIds. Express task dependencies with dependsOnKeys only when one task truly cannot start before another completes.',
|
|
407
452
|
'',
|
|
408
453
|
'Current issue:',
|
|
@@ -417,8 +462,9 @@ function buildTaskSyncPrompt(issue, input, workingDir) {
|
|
|
417
462
|
input.planOutput?.join('\n').trim(),
|
|
418
463
|
].filter(Boolean).join('\n');
|
|
419
464
|
}
|
|
420
|
-
function
|
|
465
|
+
function buildTaskAgentPrompt(issue, task, preset, workingDir) {
|
|
421
466
|
return [
|
|
467
|
+
preset.systemPrompt?.trim(),
|
|
422
468
|
'Before executing, call ViewCurrentChannelIssue with the current channel id to load the latest shared issue context and comments.',
|
|
423
469
|
`The current workspace working directory is: ${workingDir}`,
|
|
424
470
|
'Create and modify project files under this working directory. Do not place deliverables in /tmp unless the task explicitly asks for temporary scratch output.',
|
|
@@ -432,9 +478,10 @@ function buildExecutorPrompt(issue, task, workingDir) {
|
|
|
432
478
|
'',
|
|
433
479
|
'Current task:',
|
|
434
480
|
`- Task id: ${task.id}`,
|
|
481
|
+
`- Assigned agent: ${preset.name} (${preset.role})`,
|
|
435
482
|
`- Title: ${task.title}`,
|
|
436
483
|
`- Description: ${task.description}`,
|
|
437
|
-
].join('\n');
|
|
484
|
+
].filter(Boolean).join('\n');
|
|
438
485
|
}
|
|
439
486
|
function createCurrentIssueTools(workspaceId, issue, preset) {
|
|
440
487
|
const channel = channelService.getChannel(workspaceId, issue.channelId);
|
|
@@ -6,7 +6,6 @@ import * as issueService from '../services/issue.js';
|
|
|
6
6
|
import { createAgentRuntime } from '../adapters/agent-runtime.js';
|
|
7
7
|
import * as wsService from '../services/workspace.js';
|
|
8
8
|
import * as channelService from '../services/channel.js';
|
|
9
|
-
import { syncIssueTasksAfterPlanning } from './issue-task-controller.js';
|
|
10
9
|
import { completeIssueAgentProgress, createIssueAgentProgress, createIssueAgentProgressTracker } from './issue-agent-progress.js';
|
|
11
10
|
import { createIssueFunctionTools } from '../services/builtin-tools.js';
|
|
12
11
|
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
@@ -18,11 +17,8 @@ export async function runPlanner(workspaceId, issueId, ctx) {
|
|
|
18
17
|
}
|
|
19
18
|
const plannerPreset = findIssueMemberAgent(workspaceId, issue, 'planner');
|
|
20
19
|
if (!plannerPreset) {
|
|
21
|
-
console.warn(`[planner] no planner member found
|
|
22
|
-
|
|
23
|
-
planSummary: '',
|
|
24
|
-
planOutput: [],
|
|
25
|
-
}, ctx);
|
|
20
|
+
console.warn(`[planner] no planner member found workspaceId=${workspaceId} issueId=${issueId} channelId=${issue.channelId}`);
|
|
21
|
+
markIssueError(workspaceId, issueId, issue.status, 'Planner agent is not configured', ctx);
|
|
26
22
|
return;
|
|
27
23
|
}
|
|
28
24
|
const planner = agentService.getOrCreateSessionForConfig(workspaceId, plannerPreset);
|
|
@@ -105,12 +101,13 @@ export async function runPlanner(workspaceId, issueId, ctx) {
|
|
|
105
101
|
ctx.broadcast('issue.updated', erroredIssue);
|
|
106
102
|
return;
|
|
107
103
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
104
|
+
markIssueError(workspaceId, issueId, 'planned', 'Planner pipeline is disabled; issue automation is workflow-driven', ctx);
|
|
105
|
+
}
|
|
106
|
+
function markIssueError(workspaceId, issueId, from, message, ctx) {
|
|
107
|
+
const erroredIssue = issueService.markError(workspaceId, issueId, message);
|
|
108
|
+
ctx.broadcast('issue.status_changed', { issueId, from, to: 'error' });
|
|
109
|
+
if (erroredIssue)
|
|
110
|
+
ctx.broadcast('issue.updated', erroredIssue);
|
|
114
111
|
}
|
|
115
112
|
function findIssueMemberAgent(workspaceId, issue, role) {
|
|
116
113
|
const channel = channelService.getChannel(workspaceId, issue.channelId);
|
package/dist/app.js
CHANGED
|
@@ -13,12 +13,17 @@ import workspaceRouter from './routes/workspace.js';
|
|
|
13
13
|
import fileRouter from './routes/file.js';
|
|
14
14
|
import channelRouter from './routes/channel.js';
|
|
15
15
|
import issueRouter from './routes/issue.js';
|
|
16
|
+
import workflowRouter from './routes/workflow.js';
|
|
16
17
|
import agentRouter from './routes/agent.js';
|
|
17
18
|
import taskRouter from './routes/task.js';
|
|
18
19
|
import gitRouter from './routes/git.js';
|
|
19
20
|
import llmRouter from './routes/llm.js';
|
|
20
21
|
import authRouter from './routes/auth.js';
|
|
21
22
|
import folderRouter from './routes/folder.js';
|
|
23
|
+
import commandRouter from './routes/command.js';
|
|
24
|
+
import skillRouter from './routes/skill.js';
|
|
25
|
+
import mcpRouter from './routes/mcp.js';
|
|
26
|
+
import subscriptionRouter from './routes/subscription.js';
|
|
22
27
|
import { authMiddleware, verifyToken } from './middleware/auth.js';
|
|
23
28
|
import { handleConnection } from './ws/handler.js';
|
|
24
29
|
import { startScheduler, stopScheduler } from './agents/scheduler-agent.js';
|
|
@@ -69,12 +74,17 @@ app.use('/api/workspaces', workspaceRouter);
|
|
|
69
74
|
app.use('/api/workspaces/:id/files', fileRouter);
|
|
70
75
|
app.use('/api/workspaces/:id/channels', channelRouter);
|
|
71
76
|
app.use('/api/workspaces/:id/issues', issueRouter);
|
|
77
|
+
app.use('/api/workflows', workflowRouter);
|
|
78
|
+
app.use('/api/workspaces/:id/commands', commandRouter);
|
|
72
79
|
app.use('/api/workspaces/:id/agents', agentRouter);
|
|
73
80
|
app.use('/api/workspaces/:id/tasks', taskRouter);
|
|
74
81
|
app.use('/api/workspaces/:id/git', gitRouter);
|
|
75
82
|
app.use('/api/agents', agentRouter);
|
|
76
83
|
app.use('/api', llmRouter);
|
|
77
84
|
app.use('/api/folder', folderRouter);
|
|
85
|
+
app.use('/api/skills', skillRouter);
|
|
86
|
+
app.use('/api/mcps', mcpRouter);
|
|
87
|
+
app.use('/api/subscriptions', subscriptionRouter);
|
|
78
88
|
// Serve static web frontend in production (after API routes, before catch-all)
|
|
79
89
|
const webDir = resolveRuntimeDir('web');
|
|
80
90
|
if (existsSync(webDir)) {
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Agent hooks
|
|
2
|
+
* Agent hooks retained for legacy callers.
|
|
3
3
|
*/
|
|
4
|
-
import { runReviewer } from '../agents/reviewer-agent.js';
|
|
5
4
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Workflow task execution completes tasks directly. Review steps should be
|
|
6
|
+
* modeled as workflow nodes instead of this hardcoded hook.
|
|
8
7
|
*/
|
|
9
|
-
export async function onExecutorComplete(workspaceId, taskId, issueId, result,
|
|
8
|
+
export async function onExecutorComplete(workspaceId, taskId, issueId, result, _ctx) {
|
|
10
9
|
console.log(`[hook:onExecutorComplete] entered workspaceId=${workspaceId} taskId=${taskId} issueId=${issueId} success=${result.success} summary=${JSON.stringify(result.summary)}`);
|
|
11
10
|
if (!result.success) {
|
|
12
11
|
console.warn(`[hook:onExecutorComplete] task ${taskId} failed: ${result.error}`);
|
|
13
12
|
return;
|
|
14
13
|
}
|
|
15
|
-
console.log(`[hook:onExecutorComplete]
|
|
16
|
-
await runReviewer(workspaceId, taskId, issueId, result, ctx);
|
|
17
|
-
console.log(`[hook:onExecutorComplete] reviewer completed taskId=${taskId} issueId=${issueId}`);
|
|
14
|
+
console.log(`[hook:onExecutorComplete] reviewer hook skipped; workflow controls task order taskId=${taskId} issueId=${issueId}`);
|
|
18
15
|
}
|
|
19
16
|
//# sourceMappingURL=agent-hooks.js.map
|