@agent-spaces/server 0.3.65 → 0.3.67
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/agent-runtime.js +4 -0
- package/dist/adapters/codex-function-tool-bridge.js +144 -0
- package/dist/adapters/codex-runtime.js +23 -4
- package/dist/adapters/git.js +12 -1
- package/dist/adapters/hermes-runtime.js +210 -0
- package/dist/agents/issue-task-controller.js +69 -2
- package/dist/agents/pull-request-agent.js +115 -0
- package/dist/agents/scheduler-agent.js +1 -1
- package/dist/app.js +6 -2
- package/dist/middleware/auth.js +1 -1
- package/dist/package.json +2 -1
- package/dist/routes/agent-sse.js +1 -0
- package/dist/routes/issue.js +1 -1
- package/dist/routes/notification.js +10 -0
- package/dist/routes/version.js +94 -0
- package/dist/routes/worktree.js +93 -0
- package/dist/services/agent.js +1 -1
- package/dist/services/notification-center.js +9 -0
- package/dist/services/version.js +59 -0
- package/dist/services/workflow-command-runner.js +23 -0
- package/dist/services/workflow.js +25 -8
- package/dist/services/workspace.js +23 -1
- package/dist/services/worktree.js +207 -0
- package/dist/storage/worktree-store.js +33 -0
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +4 -4
- package/dist/web/__next._full.txt +21 -21
- package/dist/web/__next._head.txt +4 -4
- package/dist/web/__next._index.txt +13 -13
- package/dist/web/__next._tree.txt +2 -2
- package/dist/web/_next/static/chunks/{08x85faoz58i7.js → 0-92u-tiuy40a.js} +4 -4
- package/dist/web/_next/static/chunks/{0db14450oqzhg.js → 0-yizd8osmas2.js} +1 -1
- package/dist/web/_next/static/chunks/0.ln~3mnv8.69.js +1 -0
- package/dist/web/_next/static/chunks/{11cchuwoupmbf.js → 01y3e9pemva7b.js} +10 -10
- package/dist/web/_next/static/chunks/02l~tmzrgny.~.js +1 -0
- package/dist/web/_next/static/chunks/03f1bwuynjdmk.js +1 -0
- package/dist/web/_next/static/chunks/04cb4kc9r2pd1.js +1 -0
- package/dist/web/_next/static/chunks/04de6ha5_e3pp.js +1 -0
- package/dist/web/_next/static/chunks/09he0p79ov1rn.js +1 -0
- package/dist/web/_next/static/chunks/09vpocs4zuc8h.js +1 -0
- package/dist/web/_next/static/chunks/0_o2exgr0e_nh.js +1 -0
- package/dist/web/_next/static/chunks/{0xbaakj0dfc0..js → 0_y9nskc-xt2k.js} +1 -1
- package/dist/web/_next/static/chunks/0clnj-1fi6u8j.js +3 -0
- package/dist/web/_next/static/chunks/0gv40by0zzxs_.js +1 -0
- package/dist/web/_next/static/chunks/0iusr8y88.kjg.js +1 -0
- package/dist/web/_next/static/chunks/{0-a.-hl3wv99k.js → 0j-8418fxvkd1.js} +1 -1
- package/dist/web/_next/static/chunks/0j.wxxyoclma5.js +1 -0
- package/dist/web/_next/static/chunks/{0.6b64sy0g5.3.js → 0jq.16sozqik..js} +1 -1
- package/dist/web/_next/static/chunks/0jw8xdk_fpnp0.css +1 -0
- package/dist/web/_next/static/chunks/0l1lkd-wcotma.js +1 -0
- package/dist/web/_next/static/chunks/{0u6h-hqc_i52e.js → 0ncxf_zr4n839.js} +1 -1
- package/dist/web/_next/static/chunks/0ndo7um~v7vco.js +1 -0
- package/dist/web/_next/static/chunks/0ngk.~kan8wq_.js +1 -0
- package/dist/web/_next/static/chunks/0ppr271hz0xoq.js +1 -0
- package/dist/web/_next/static/chunks/0rt9bofnn6qvn.js +1 -0
- package/dist/web/_next/static/chunks/0t64.9jd00hio.js +3 -0
- package/dist/web/_next/static/chunks/0taui9--5n6-5.js +1 -0
- package/dist/web/_next/static/chunks/0ty39169lh~z3.js +1 -0
- package/dist/web/_next/static/chunks/0v8nof~waedlu.js +1 -0
- package/dist/web/_next/static/chunks/{0-pi.67w.ymsr.js → 0vcfoagnpf.aw.js} +1 -1
- package/dist/web/_next/static/chunks/{0vis~lx0nxgn-.js → 0wwwq.gyyz0vg.js} +3 -3
- package/dist/web/_next/static/chunks/0x5lak8yz7pm7.js +1 -0
- package/dist/web/_next/static/chunks/0xon_.4-o0_zq.js +7 -0
- package/dist/web/_next/static/chunks/0zjnrbt7inime.js +1 -0
- package/dist/web/_next/static/chunks/0zwebpitvpuv1.js +1 -0
- package/dist/web/_next/static/chunks/0~02o4g-o6n~m.js +1 -0
- package/dist/web/_next/static/chunks/{0w7.tb29958zj.js → 0~fjezp.k4qk3.js} +1 -1
- package/dist/web/_next/static/chunks/0~sh93re1-_rp.js +1 -0
- package/dist/web/_next/static/chunks/10_niiq0k6o-p.js +5 -0
- package/dist/web/_next/static/chunks/12tjr0_2ccrtq.js +2 -0
- package/dist/web/_next/static/chunks/12x5.go_x9mfk.js +1 -0
- package/dist/web/_next/static/chunks/{0l2w0qz1ea7ql.js → 12~5dk9i9d16t.js} +2 -2
- package/dist/web/_next/static/chunks/13iye4rv5p31b.js +1 -0
- package/dist/web/_next/static/chunks/{01~quun6sefgl.js → 13~y-b.b9rrw4.js} +1 -1
- package/dist/web/_next/static/chunks/151wzhb5q0lo5.js +1 -0
- package/dist/web/_not-found/__next._full.txt +19 -19
- package/dist/web/_not-found/__next._head.txt +4 -4
- package/dist/web/_not-found/__next._index.txt +13 -13
- 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 +19 -19
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +21 -21
- package/dist/web/login/__next._full.txt +21 -21
- package/dist/web/login/__next._head.txt +4 -4
- package/dist/web/login/__next._index.txt +13 -13
- 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 +21 -21
- package/dist/web/settings/__next._full.txt +23 -23
- package/dist/web/settings/__next._head.txt +4 -4
- package/dist/web/settings/__next._index.txt +13 -13
- package/dist/web/settings/__next._tree.txt +2 -2
- package/dist/web/settings/__next.settings.__PAGE__.txt +4 -4
- package/dist/web/settings/__next.settings.txt +5 -5
- package/dist/web/settings/agents/__next._full.txt +23 -23
- package/dist/web/settings/agents/__next._head.txt +4 -4
- package/dist/web/settings/agents/__next._index.txt +13 -13
- package/dist/web/settings/agents/__next._tree.txt +2 -2
- package/dist/web/settings/agents/__next.settings.agents.__PAGE__.txt +4 -4
- package/dist/web/settings/agents/__next.settings.agents.txt +3 -3
- package/dist/web/settings/agents/__next.settings.txt +5 -5
- package/dist/web/settings/agents.html +1 -1
- package/dist/web/settings/agents.txt +23 -23
- package/dist/web/settings/mcps/__next._full.txt +23 -23
- package/dist/web/settings/mcps/__next._head.txt +4 -4
- package/dist/web/settings/mcps/__next._index.txt +13 -13
- package/dist/web/settings/mcps/__next._tree.txt +2 -2
- package/dist/web/settings/mcps/__next.settings.mcps.__PAGE__.txt +4 -4
- package/dist/web/settings/mcps/__next.settings.mcps.txt +3 -3
- package/dist/web/settings/mcps/__next.settings.txt +5 -5
- package/dist/web/settings/mcps.html +1 -1
- package/dist/web/settings/mcps.txt +23 -23
- package/dist/web/settings/models/__next._full.txt +23 -23
- package/dist/web/settings/models/__next._head.txt +4 -4
- package/dist/web/settings/models/__next._index.txt +13 -13
- package/dist/web/settings/models/__next._tree.txt +2 -2
- package/dist/web/settings/models/__next.settings.models.__PAGE__.txt +4 -4
- package/dist/web/settings/models/__next.settings.models.txt +3 -3
- package/dist/web/settings/models/__next.settings.txt +5 -5
- package/dist/web/settings/models.html +1 -1
- package/dist/web/settings/models.txt +23 -23
- package/dist/web/settings/output-styles/__next._full.txt +23 -23
- package/dist/web/settings/output-styles/__next._head.txt +4 -4
- package/dist/web/settings/output-styles/__next._index.txt +13 -13
- package/dist/web/settings/output-styles/__next._tree.txt +2 -2
- package/dist/web/settings/output-styles/__next.settings.output-styles.__PAGE__.txt +4 -4
- package/dist/web/settings/output-styles/__next.settings.output-styles.txt +3 -3
- package/dist/web/settings/output-styles/__next.settings.txt +5 -5
- package/dist/web/settings/output-styles.html +1 -1
- package/dist/web/settings/output-styles.txt +23 -23
- package/dist/web/settings/prompts/__next._full.txt +23 -23
- package/dist/web/settings/prompts/__next._head.txt +4 -4
- package/dist/web/settings/prompts/__next._index.txt +13 -13
- package/dist/web/settings/prompts/__next._tree.txt +2 -2
- package/dist/web/settings/prompts/__next.settings.prompts.__PAGE__.txt +4 -4
- package/dist/web/settings/prompts/__next.settings.prompts.txt +3 -3
- package/dist/web/settings/prompts/__next.settings.txt +5 -5
- package/dist/web/settings/prompts.html +1 -1
- package/dist/web/settings/prompts.txt +23 -23
- package/dist/web/settings/providers/__next._full.txt +23 -23
- package/dist/web/settings/providers/__next._head.txt +4 -4
- package/dist/web/settings/providers/__next._index.txt +13 -13
- package/dist/web/settings/providers/__next._tree.txt +2 -2
- package/dist/web/settings/providers/__next.settings.providers.__PAGE__.txt +4 -4
- package/dist/web/settings/providers/__next.settings.providers.txt +3 -3
- package/dist/web/settings/providers/__next.settings.txt +5 -5
- package/dist/web/settings/providers.html +1 -1
- package/dist/web/settings/providers.txt +23 -23
- package/dist/web/settings/skills/__next._full.txt +23 -23
- package/dist/web/settings/skills/__next._head.txt +4 -4
- package/dist/web/settings/skills/__next._index.txt +13 -13
- package/dist/web/settings/skills/__next._tree.txt +2 -2
- package/dist/web/settings/skills/__next.settings.skills.__PAGE__.txt +4 -4
- package/dist/web/settings/skills/__next.settings.skills.txt +3 -3
- package/dist/web/settings/skills/__next.settings.txt +5 -5
- package/dist/web/settings/skills.html +1 -1
- package/dist/web/settings/skills.txt +23 -23
- package/dist/web/settings/tools/__next._full.txt +23 -23
- package/dist/web/settings/tools/__next._head.txt +4 -4
- package/dist/web/settings/tools/__next._index.txt +13 -13
- package/dist/web/settings/tools/__next._tree.txt +2 -2
- package/dist/web/settings/tools/__next.settings.tools.__PAGE__.txt +4 -4
- package/dist/web/settings/tools/__next.settings.tools.txt +3 -3
- package/dist/web/settings/tools/__next.settings.txt +5 -5
- package/dist/web/settings/tools.html +1 -1
- package/dist/web/settings/tools.txt +23 -23
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +23 -23
- package/dist/web/workflows/__next._full.txt +22 -22
- package/dist/web/workflows/__next._head.txt +4 -4
- package/dist/web/workflows/__next._index.txt +13 -13
- package/dist/web/workflows/__next._tree.txt +2 -2
- package/dist/web/workflows/__next.workflows.__PAGE__.txt +4 -4
- package/dist/web/workflows/__next.workflows.txt +3 -3
- package/dist/web/workflows.html +1 -1
- package/dist/web/workflows.txt +22 -22
- package/dist/web/workspace/_/__next._full.txt +20 -20
- package/dist/web/workspace/_/__next._head.txt +4 -4
- package/dist/web/workspace/_/__next._index.txt +13 -13
- 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 +20 -20
- package/dist/web/workspaces/__next._full.txt +21 -21
- package/dist/web/workspaces/__next._head.txt +4 -4
- package/dist/web/workspaces/__next._index.txt +13 -13
- 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 +21 -21
- package/dist/ws/agent-prompt.js +32 -3
- package/dist/ws/agent-runner.js +1 -0
- package/package.json +2 -1
- package/dist/web/_next/static/chunks/0-v_p6j5u3_9l.js +0 -1
- package/dist/web/_next/static/chunks/0.-x29t-8gk0r.js +0 -1
- package/dist/web/_next/static/chunks/0.l5e8~r7_0~p.js +0 -1
- package/dist/web/_next/static/chunks/0.n~yfwf4~6w-.js +0 -1
- package/dist/web/_next/static/chunks/00-syqzi-6zxr.js +0 -1
- package/dist/web/_next/static/chunks/02j4sr9psucf-.js +0 -1
- package/dist/web/_next/static/chunks/06si8l0doqe8p.js +0 -1
- package/dist/web/_next/static/chunks/08kfx8on9oty~.js +0 -1
- package/dist/web/_next/static/chunks/08ugbvzr20drp.js +0 -2
- package/dist/web/_next/static/chunks/0_cqojbge48kq.js +0 -5
- package/dist/web/_next/static/chunks/0d6~~lv0-6kex.js +0 -3
- package/dist/web/_next/static/chunks/0gdwop9cnpmtu.js +0 -1
- package/dist/web/_next/static/chunks/0ghx3j_.-gdyd.js +0 -1
- package/dist/web/_next/static/chunks/0kbvoxla7f751.js +0 -1
- package/dist/web/_next/static/chunks/0paaat8y96ayc.js +0 -7
- package/dist/web/_next/static/chunks/0pq318f8xgafg.js +0 -1
- package/dist/web/_next/static/chunks/0t6s8of0qr6nc.js +0 -1
- package/dist/web/_next/static/chunks/0xt-8wk21gs7g.js +0 -1
- package/dist/web/_next/static/chunks/0yd.m1afqg.2t.js +0 -3
- package/dist/web/_next/static/chunks/0yhbr8hl09b-5.js +0 -1
- package/dist/web/_next/static/chunks/0z~vqzbm_q371.js +0 -1
- package/dist/web/_next/static/chunks/0~~_ltu6dx_ch.js +0 -1
- package/dist/web/_next/static/chunks/12oxcgyhpaxw~.js +0 -1
- package/dist/web/_next/static/chunks/1452eibz62gs6.css +0 -1
- package/dist/web/_next/static/chunks/16zlreiems5cn.js +0 -1
- package/dist/web/_next/static/chunks/18awqjk9-o5m0.js +0 -1
- /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{x4-CsKe6qUQyFDWVtfvUg → rGXyAK8rgod1NjF3bLZAY}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import * as agentService from '../services/agent.js';
|
|
2
|
+
import { AGENT_GENERATOR_PRESET_ID } from '../services/agent.js';
|
|
3
|
+
import { createAgentRuntime } from '../adapters/agent-runtime.js';
|
|
4
|
+
import { getWorkspace } from '../storage/workspace-store.js';
|
|
5
|
+
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
6
|
+
import { prependPersistentAgentContext } from '../services/persistent-agent-context.js';
|
|
7
|
+
const DEFAULT_SYSTEM_PROMPT = [
|
|
8
|
+
'You are a pull request description generator.',
|
|
9
|
+
'Return a concise, useful PR body based only on the provided commits and diff.',
|
|
10
|
+
'Use Markdown with these sections: Summary and Changes.',
|
|
11
|
+
'Keep it short. Do not greet, explain your process, ask questions, provide options, or wrap the response in code fences.',
|
|
12
|
+
'Output only the final PR body text.',
|
|
13
|
+
].join(' ');
|
|
14
|
+
export async function runPullRequestAgent(workspaceId, input) {
|
|
15
|
+
const ws = getWorkspace(workspaceId);
|
|
16
|
+
if (!ws)
|
|
17
|
+
throw new Error('Workspace not found');
|
|
18
|
+
if (!input.diff.trim() && input.commits.length === 0)
|
|
19
|
+
throw new Error('No changes found');
|
|
20
|
+
const agent = findPullRequestAgent(workspaceId);
|
|
21
|
+
const session = agentService.getOrCreateSessionForConfig(workspaceId, agent);
|
|
22
|
+
agentService.updateStatus(workspaceId, session.id, 'active');
|
|
23
|
+
const runtime = createAgentRuntime({
|
|
24
|
+
kind: agent.runtimeKind,
|
|
25
|
+
provider: agent.modelProvider,
|
|
26
|
+
model: agent.modelId,
|
|
27
|
+
apiKey: agent.apiKey,
|
|
28
|
+
baseURL: agent.apiBase,
|
|
29
|
+
...getThinkingRuntimeConfig(agent),
|
|
30
|
+
});
|
|
31
|
+
const workingDir = agentService.resolveWorkingDir(workspaceId, agent);
|
|
32
|
+
const systemPrompt = DEFAULT_SYSTEM_PROMPT;
|
|
33
|
+
const truncatedDiff = input.diff.length > 12000
|
|
34
|
+
? `${input.diff.substring(0, 12000)}\n... (truncated)`
|
|
35
|
+
: input.diff;
|
|
36
|
+
const userPrompt = [
|
|
37
|
+
`Generate a pull request body for branch ${input.worktree.branch} targeting ${input.baseBranch}.`,
|
|
38
|
+
'',
|
|
39
|
+
'Commits:',
|
|
40
|
+
input.commits.length > 0 ? input.commits.map((commit) => `- ${commit}`).join('\n') : '- No commit messages available',
|
|
41
|
+
'',
|
|
42
|
+
'Diff:',
|
|
43
|
+
truncatedDiff,
|
|
44
|
+
].join('\n');
|
|
45
|
+
const result = await runtime.execute(prependPersistentAgentContext(userPrompt, {
|
|
46
|
+
workspaceId,
|
|
47
|
+
workingDir,
|
|
48
|
+
boundDirs: ws.boundDirs,
|
|
49
|
+
includeWorkspacePrompt: false,
|
|
50
|
+
excludeNativeClaudeMd: agent.runtimeKind === 'claude-code',
|
|
51
|
+
}), workingDir, {
|
|
52
|
+
maxTurns: 1,
|
|
53
|
+
userPrompt,
|
|
54
|
+
systemPrompt,
|
|
55
|
+
outputStyle: agent.outputStyle,
|
|
56
|
+
});
|
|
57
|
+
agentService.complete(workspaceId, session.id, result.success ? undefined : result.error, {
|
|
58
|
+
runtime: agent.runtimeKind,
|
|
59
|
+
model: agent.modelId,
|
|
60
|
+
summary: result.summary,
|
|
61
|
+
output: result.output,
|
|
62
|
+
usage: result.usage,
|
|
63
|
+
costUsd: result.costUsd,
|
|
64
|
+
});
|
|
65
|
+
if (!result.success) {
|
|
66
|
+
throw new Error(result.error || 'Pull request agent failed');
|
|
67
|
+
}
|
|
68
|
+
const body = sanitizePullRequestBody(result.output);
|
|
69
|
+
if (!body)
|
|
70
|
+
throw new Error('Empty response from pull request agent');
|
|
71
|
+
return body;
|
|
72
|
+
}
|
|
73
|
+
function findPullRequestAgent(workspaceId) {
|
|
74
|
+
const presets = agentService.listPresets(workspaceId);
|
|
75
|
+
const preset = presets?.find((a) => a.id === AGENT_GENERATOR_PRESET_ID);
|
|
76
|
+
if (preset)
|
|
77
|
+
return preset;
|
|
78
|
+
const template = agentService.readAgentTemplate(AGENT_GENERATOR_PRESET_ID);
|
|
79
|
+
if (template)
|
|
80
|
+
return template;
|
|
81
|
+
return agentService.listTemplates().find((a) => a.id === AGENT_GENERATOR_PRESET_ID) ?? agentService.listTemplates()[0];
|
|
82
|
+
}
|
|
83
|
+
function sanitizePullRequestBody(output) {
|
|
84
|
+
const chunks = (Array.isArray(output) ? output : [output])
|
|
85
|
+
.map((chunk) => cleanOutputChunk(chunk))
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
const uniqueChunks = dedupeAdjacentChunks(chunks);
|
|
88
|
+
return (uniqueChunks.at(-1) || uniqueChunks.join('\n\n')).trim();
|
|
89
|
+
}
|
|
90
|
+
function cleanOutputChunk(chunk) {
|
|
91
|
+
return chunk
|
|
92
|
+
.split('\n')
|
|
93
|
+
.filter((line) => !isRuntimeNoise(line))
|
|
94
|
+
.join('\n')
|
|
95
|
+
.replace(/```(?:\w+)?\n([\s\S]*?)```/g, '$1')
|
|
96
|
+
.trim();
|
|
97
|
+
}
|
|
98
|
+
function dedupeAdjacentChunks(chunks) {
|
|
99
|
+
const result = [];
|
|
100
|
+
for (const chunk of chunks) {
|
|
101
|
+
if (result.at(-1)?.trim() === chunk.trim())
|
|
102
|
+
continue;
|
|
103
|
+
result.push(chunk);
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
function isRuntimeNoise(line) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
return /^\[Usage\]/.test(trimmed)
|
|
110
|
+
|| /^Claude Code initialized\b/i.test(trimmed)
|
|
111
|
+
|| /^Codex initialized\b/i.test(trimmed)
|
|
112
|
+
|| /^Tool:/i.test(trimmed)
|
|
113
|
+
|| /^Todo:/i.test(trimmed);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=pull-request-agent.js.map
|
|
@@ -16,7 +16,7 @@ export function startScheduler(workspaceId, ctx) {
|
|
|
16
16
|
const tick = async () => {
|
|
17
17
|
// 检查 workspace 是否关闭了自动处理
|
|
18
18
|
const workspace = workspaceService.getById(workspaceId);
|
|
19
|
-
if (workspace && workspace.autoProcessIssues
|
|
19
|
+
if (workspace && workspace.autoProcessIssues !== true) {
|
|
20
20
|
console.log(`[scheduler:${workspaceId}] auto-processing disabled for this workspace, skip`);
|
|
21
21
|
return;
|
|
22
22
|
}
|
package/dist/app.js
CHANGED
|
@@ -33,16 +33,18 @@ import searchRouter from './routes/search.js';
|
|
|
33
33
|
import notificationRouter from './routes/notification.js';
|
|
34
34
|
import databaseRouter from './routes/database.js';
|
|
35
35
|
import kanbanRouter from './routes/kanban.js';
|
|
36
|
+
import { worktreeRouter } from './routes/worktree.js';
|
|
36
37
|
import speechRecognitionRouter, { handleSpeechStream } from './routes/speech-recognition.js';
|
|
37
38
|
import agentCommandsRouter from './routes/agent-commands.js';
|
|
38
39
|
import robotAccountRouter from './routes/robot-account.js';
|
|
40
|
+
import versionRouter from './routes/version.js';
|
|
39
41
|
import { getUserSettings, setUserAvatarUrl, removeUserAvatarUrl } from './storage/user-settings-store.js';
|
|
40
42
|
import { authMiddleware, verifyToken } from './middleware/auth.js';
|
|
41
43
|
import { handleConnection } from './ws/handler.js';
|
|
42
44
|
import { handleTypeScriptLspConnection } from './ws/typescript-lsp.js';
|
|
43
45
|
import { broadcastToAll } from './ws/connection-manager.js';
|
|
44
46
|
import { startScheduler, stopScheduler } from './agents/scheduler-agent.js';
|
|
45
|
-
import { recoverRunningWorkOnStartup } from './services/issue-retry.js';
|
|
47
|
+
// import { recoverRunningWorkOnStartup } from './services/issue-retry.js';
|
|
46
48
|
import { startPersistedNotificationServices } from './services/notification-hub/index.js';
|
|
47
49
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
48
50
|
const PORT = parseInt(process.env.PORT || '3100', 10);
|
|
@@ -191,6 +193,7 @@ app.post('/api/git-config', async (req, res) => {
|
|
|
191
193
|
app.use('/api/workspaces/:id/search', searchRouter);
|
|
192
194
|
app.use('/api/workspaces/:id/database', databaseRouter);
|
|
193
195
|
app.use('/api/workspaces/:id/kanban', kanbanRouter);
|
|
196
|
+
app.use('/api/workspaces/:id/worktrees', worktreeRouter);
|
|
194
197
|
app.use('/api/workspaces/:id/notifications', notificationRouter);
|
|
195
198
|
app.use('/api/agents', agentRouter);
|
|
196
199
|
app.use('/api', llmRouter);
|
|
@@ -203,6 +206,7 @@ app.use('/api/subscriptions', subscriptionRouter);
|
|
|
203
206
|
app.use('/api/speech-recognition', speechRecognitionRouter);
|
|
204
207
|
app.use('/api/agent-commands', agentCommandsRouter);
|
|
205
208
|
app.use('/api/robot-accounts', robotAccountRouter);
|
|
209
|
+
app.use('/api', versionRouter);
|
|
206
210
|
// Serve static web frontend in production (after API routes, before catch-all)
|
|
207
211
|
const webDir = resolveRuntimeDir('web');
|
|
208
212
|
if (existsSync(webDir)) {
|
|
@@ -296,7 +300,7 @@ const HOST = process.env.HOST || '0.0.0.0';
|
|
|
296
300
|
server.listen(PORT, HOST, () => {
|
|
297
301
|
console.log(`[server] listening on http://${HOST}:${PORT}`);
|
|
298
302
|
console.log(`[server] websocket on ws://${HOST}:${PORT}/ws?workspaceId=...`);
|
|
299
|
-
recoverRunningWorkOnStartup();
|
|
303
|
+
// recoverRunningWorkOnStartup();
|
|
300
304
|
startPersistedNotificationServices().catch((err) => {
|
|
301
305
|
console.error('[notification] failed to restore persisted services:', err);
|
|
302
306
|
});
|
package/dist/middleware/auth.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getSecret } from '../services/auth-store.js';
|
|
2
2
|
export function authMiddleware(req, res, next) {
|
|
3
3
|
const secret = getSecret();
|
|
4
|
-
const openPaths = ['/api/health', '/api/auth/login', '/api/auth/check'];
|
|
4
|
+
const openPaths = ['/api/health', '/api/auth/login', '/api/auth/check', '/api/version', '/api/version/check'];
|
|
5
5
|
if (openPaths.includes(req.path))
|
|
6
6
|
return next();
|
|
7
7
|
const auth = req.headers.authorization;
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-spaces/server",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.66",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "app.js",
|
|
6
6
|
"packageManager": "pnpm@10.17.1",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"@langchain/google-genai": "^2.1.30",
|
|
17
17
|
"@langchain/openai": "^1.4.5",
|
|
18
18
|
"@larksuiteoapi/node-sdk": "^1.62.1",
|
|
19
|
+
"@modelcontextprotocol/sdk": "1.29.0",
|
|
19
20
|
"@openai/codex-sdk": "^0.128.0",
|
|
20
21
|
"cors": "^2.8.5",
|
|
21
22
|
"dotenv": "^17.4.2",
|
package/dist/routes/agent-sse.js
CHANGED
|
@@ -67,6 +67,7 @@ router.post('/run', async (req, res) => {
|
|
|
67
67
|
agentService.updateStatus(workspaceId, session.id, 'active');
|
|
68
68
|
writeSse(res, 'status', { agentId: session.id, status: 'active' });
|
|
69
69
|
const result = await runtime.execute(buildAgentPrompt(workspaceId, body.systemPrompt ?? preset.systemPrompt, userPrompt, normalizeMessages(body.messages), {
|
|
70
|
+
runtimeKind: preset.runtimeKind,
|
|
70
71
|
mcpServers: Object.keys(mcpServers ?? {}),
|
|
71
72
|
skills,
|
|
72
73
|
boundDirs: workspace.boundDirs,
|
package/dist/routes/issue.js
CHANGED
|
@@ -313,7 +313,7 @@ function mergeWorkflowMembers(members, workflowId) {
|
|
|
313
313
|
return base;
|
|
314
314
|
return Array.from(new Set([
|
|
315
315
|
...base,
|
|
316
|
-
...workflow.nodes.map((node) => node.data.agentConfigId).filter(Boolean),
|
|
316
|
+
...workflow.nodes.filter((n) => n.type === 'agent').map((node) => node.data.agentConfigId).filter(Boolean),
|
|
317
317
|
]));
|
|
318
318
|
}
|
|
319
319
|
//# sourceMappingURL=issue.js.map
|
|
@@ -27,5 +27,15 @@ router.delete('/', (req, res) => {
|
|
|
27
27
|
nc.clearAll(workspaceId);
|
|
28
28
|
res.json({ ok: true });
|
|
29
29
|
});
|
|
30
|
+
router.delete('/:notificationId', (req, res) => {
|
|
31
|
+
const workspaceId = req.params.id;
|
|
32
|
+
const notificationId = req.params.notificationId;
|
|
33
|
+
const removed = nc.removeNotification(workspaceId, notificationId);
|
|
34
|
+
if (!removed) {
|
|
35
|
+
res.status(404).json({ error: 'Not found' });
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
res.json({ ok: true });
|
|
39
|
+
});
|
|
30
40
|
export default router;
|
|
31
41
|
//# sourceMappingURL=notification.js.map
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { spawn } from 'node:child_process';
|
|
3
|
+
import { writeFileSync, unlinkSync } from 'node:fs';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { getLocalVersion, getCachedLatest, fetchLatestVersion, isNewerVersion } from '../services/version.js';
|
|
7
|
+
const router = Router();
|
|
8
|
+
const isDev = !process.env.NODE_ENV || process.env.NODE_ENV === 'development';
|
|
9
|
+
let isUpdating = false;
|
|
10
|
+
// GET /version — cached version info (openPaths in auth.ts)
|
|
11
|
+
router.get('/version', async (_req, res) => {
|
|
12
|
+
const local = getLocalVersion();
|
|
13
|
+
if (isDev) {
|
|
14
|
+
res.json({ local, latest: null, updateAvailable: false, dev: true });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let latest = getCachedLatest();
|
|
18
|
+
if (!latest) {
|
|
19
|
+
latest = await fetchLatestVersion(false);
|
|
20
|
+
}
|
|
21
|
+
res.json({ local, latest, updateAvailable: latest ? isNewerVersion(latest, local) : false });
|
|
22
|
+
});
|
|
23
|
+
// GET /version/check — force npm lookup (openPaths in auth.ts)
|
|
24
|
+
router.get('/version/check', async (_req, res) => {
|
|
25
|
+
const local = getLocalVersion();
|
|
26
|
+
if (isDev) {
|
|
27
|
+
res.json({ local, latest: null, updateAvailable: false, dev: true });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const latest = await fetchLatestVersion(true);
|
|
31
|
+
res.json({
|
|
32
|
+
local,
|
|
33
|
+
latest,
|
|
34
|
+
updateAvailable: latest ? isNewerVersion(latest, local) : false,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
// POST /version/update — trigger self-update (requires auth)
|
|
38
|
+
router.post('/version/update', (_req, res) => {
|
|
39
|
+
if (isDev) {
|
|
40
|
+
res.status(403).json({ error: 'Updates are disabled in development mode' });
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (isUpdating) {
|
|
44
|
+
res.status(409).json({ error: 'Update already in progress' });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
isUpdating = true;
|
|
48
|
+
const pid = process.pid;
|
|
49
|
+
const ppid = process.ppid;
|
|
50
|
+
const projectRoot = join(import.meta.dirname, '..', '..');
|
|
51
|
+
const isWin = process.platform === 'win32';
|
|
52
|
+
let scriptPath;
|
|
53
|
+
if (isWin) {
|
|
54
|
+
scriptPath = join(tmpdir(), `agent-spaces-update-${pid}.cmd`);
|
|
55
|
+
const cmd = [
|
|
56
|
+
'@echo off',
|
|
57
|
+
'timeout /t 2 /nobreak >nul',
|
|
58
|
+
`taskkill /pid ${ppid} /f /t >nul 2>&1`,
|
|
59
|
+
`taskkill /pid ${pid} /f /t >nul 2>&1`,
|
|
60
|
+
`cd /d "${projectRoot}"`,
|
|
61
|
+
'call pnpm install',
|
|
62
|
+
'call pnpm start',
|
|
63
|
+
].join('\r\n');
|
|
64
|
+
writeFileSync(scriptPath, cmd, 'utf-8');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
scriptPath = join(tmpdir(), `agent-spaces-update-${pid}.sh`);
|
|
68
|
+
const sh = [
|
|
69
|
+
'#!/bin/sh',
|
|
70
|
+
'sleep 2',
|
|
71
|
+
`kill -9 ${ppid} 2>/dev/null || true`,
|
|
72
|
+
`kill -9 ${pid} 2>/dev/null || true`,
|
|
73
|
+
`cd "${projectRoot}"`,
|
|
74
|
+
'pnpm install',
|
|
75
|
+
'pnpm start',
|
|
76
|
+
].join('\n');
|
|
77
|
+
writeFileSync(scriptPath, sh, 'utf-8');
|
|
78
|
+
}
|
|
79
|
+
const child = spawn(isWin ? 'cmd' : '/bin/sh', isWin ? ['/c', scriptPath] : [scriptPath], {
|
|
80
|
+
detached: true,
|
|
81
|
+
stdio: 'ignore',
|
|
82
|
+
windowsHide: true,
|
|
83
|
+
});
|
|
84
|
+
child.unref();
|
|
85
|
+
setTimeout(() => {
|
|
86
|
+
try {
|
|
87
|
+
unlinkSync(scriptPath);
|
|
88
|
+
}
|
|
89
|
+
catch { }
|
|
90
|
+
}, 10_000);
|
|
91
|
+
res.json({ ok: true });
|
|
92
|
+
});
|
|
93
|
+
export default router;
|
|
94
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { listWorkspaceWorktrees, getWorkspaceWorktree, createWorkspaceWorktree, deleteWorkspaceWorktree, getWorktreeDiff, createWorktreePR, mergeWorktreePR, getWorktreePRDraft, } from '../services/worktree.js';
|
|
4
|
+
export const worktreeRouter = Router({ mergeParams: true });
|
|
5
|
+
const createSchema = z.object({
|
|
6
|
+
name: z.string().min(1),
|
|
7
|
+
branch: z.string().optional(),
|
|
8
|
+
agentId: z.string().optional(),
|
|
9
|
+
issueId: z.string().optional(),
|
|
10
|
+
taskId: z.string().optional(),
|
|
11
|
+
});
|
|
12
|
+
const prSchema = z.object({
|
|
13
|
+
title: z.string().optional(),
|
|
14
|
+
body: z.string().optional(),
|
|
15
|
+
});
|
|
16
|
+
const prDraftSchema = z.object({
|
|
17
|
+
title: z.string().optional(),
|
|
18
|
+
});
|
|
19
|
+
worktreeRouter.get('/', (req, res) => {
|
|
20
|
+
const { id } = req.params;
|
|
21
|
+
res.json(listWorkspaceWorktrees(id));
|
|
22
|
+
});
|
|
23
|
+
worktreeRouter.post('/', async (req, res) => {
|
|
24
|
+
try {
|
|
25
|
+
const { id } = req.params;
|
|
26
|
+
const input = createSchema.parse(req.body);
|
|
27
|
+
const info = await createWorkspaceWorktree(id, input);
|
|
28
|
+
res.status(201).json(info);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
res.status(400).json({ error: err.message });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
worktreeRouter.get('/:wtId', (req, res) => {
|
|
35
|
+
const { id, wtId } = req.params;
|
|
36
|
+
const info = getWorkspaceWorktree(id, wtId);
|
|
37
|
+
if (!info)
|
|
38
|
+
return res.status(404).json({ error: 'Worktree not found' });
|
|
39
|
+
res.json(info);
|
|
40
|
+
});
|
|
41
|
+
worktreeRouter.delete('/:wtId', async (req, res) => {
|
|
42
|
+
try {
|
|
43
|
+
const { id, wtId } = req.params;
|
|
44
|
+
await deleteWorkspaceWorktree(id, wtId);
|
|
45
|
+
res.json({ ok: true });
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
res.status(400).json({ error: err.message });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
worktreeRouter.get('/:wtId/diff', async (req, res) => {
|
|
52
|
+
try {
|
|
53
|
+
const { id, wtId } = req.params;
|
|
54
|
+
const diffs = await getWorktreeDiff(id, wtId);
|
|
55
|
+
res.json(diffs);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
res.status(400).json({ error: err.message });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
worktreeRouter.post('/:wtId/pr', async (req, res) => {
|
|
62
|
+
try {
|
|
63
|
+
const { id, wtId } = req.params;
|
|
64
|
+
const { title, body } = prSchema.parse(req.body);
|
|
65
|
+
const prUrl = await createWorktreePR(id, wtId, title, body);
|
|
66
|
+
res.json({ prUrl });
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
res.status(400).json({ error: err.message });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
worktreeRouter.post('/:wtId/pr/draft', async (req, res) => {
|
|
73
|
+
try {
|
|
74
|
+
const { id, wtId } = req.params;
|
|
75
|
+
const { title } = prDraftSchema.parse(req.body);
|
|
76
|
+
const draft = await getWorktreePRDraft(id, wtId, title);
|
|
77
|
+
res.json(draft);
|
|
78
|
+
}
|
|
79
|
+
catch (err) {
|
|
80
|
+
res.status(400).json({ error: err.message });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
worktreeRouter.post('/:wtId/merge', async (req, res) => {
|
|
84
|
+
try {
|
|
85
|
+
const { id, wtId } = req.params;
|
|
86
|
+
await mergeWorktreePR(id, wtId);
|
|
87
|
+
res.json({ ok: true });
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
res.status(400).json({ error: err.message });
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=worktree.js.map
|
package/dist/services/agent.js
CHANGED
|
@@ -11,7 +11,7 @@ import { extractUsageFromOutput } from '../storage/usage.js';
|
|
|
11
11
|
const DEFAULT_AGENT_ROLE = 'agent';
|
|
12
12
|
export const AGENT_GENERATOR_PRESET_ID = 'agent-generator';
|
|
13
13
|
export const AGENT_COMMIT_PRESET_ID = 'commit-agent';
|
|
14
|
-
const VALID_RUNTIME_KINDS = ['open-agent-sdk', 'claude-code', 'codex', 'langchain'];
|
|
14
|
+
const VALID_RUNTIME_KINDS = ['open-agent-sdk', 'claude-code', 'codex', 'langchain', 'hermes'];
|
|
15
15
|
const VALID_TOOL_NAMES = new Set(BUILT_IN_AGENT_TOOLS.map((tool) => tool.name));
|
|
16
16
|
const CLAUDE_BUILT_IN_DIRS = ['agents', 'commands'];
|
|
17
17
|
const ANTHROPIC_BRIDGE_PROVIDERS = [
|
|
@@ -46,6 +46,15 @@ export function clearAll(workspaceId) {
|
|
|
46
46
|
writeAll(workspaceId, []);
|
|
47
47
|
broadcastToWorkspace(workspaceId, 'notification.cleared', null);
|
|
48
48
|
}
|
|
49
|
+
export function removeNotification(workspaceId, notificationId) {
|
|
50
|
+
const all = readAll(workspaceId);
|
|
51
|
+
const idx = all.findIndex((n) => n.id === notificationId);
|
|
52
|
+
if (idx === -1)
|
|
53
|
+
return null;
|
|
54
|
+
const [removed] = all.splice(idx, 1);
|
|
55
|
+
writeAll(workspaceId, all);
|
|
56
|
+
return removed;
|
|
57
|
+
}
|
|
49
58
|
export function unreadCount(workspaceId) {
|
|
50
59
|
return readAll(workspaceId).filter((n) => !n.read).length;
|
|
51
60
|
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
5
|
+
let localVersion = '';
|
|
6
|
+
let cachedLatest = null;
|
|
7
|
+
const CACHE_TTL = 3600_000; // 1 hour
|
|
8
|
+
export function getLocalVersion() {
|
|
9
|
+
if (localVersion !== '')
|
|
10
|
+
return localVersion;
|
|
11
|
+
try {
|
|
12
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
13
|
+
localVersion = pkg.version || '0.0.0';
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
localVersion = '0.0.0';
|
|
17
|
+
}
|
|
18
|
+
return localVersion;
|
|
19
|
+
}
|
|
20
|
+
export function getCachedLatest() {
|
|
21
|
+
if (cachedLatest && Date.now() - cachedLatest.ts < CACHE_TTL) {
|
|
22
|
+
return cachedLatest.version;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
export async function fetchLatestVersion(forceRefresh = false) {
|
|
27
|
+
if (!forceRefresh && cachedLatest && Date.now() - cachedLatest.ts < CACHE_TTL) {
|
|
28
|
+
return cachedLatest.version;
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
const res = await fetch('https://registry.npmjs.org/@agent-spaces/server', {
|
|
32
|
+
signal: AbortSignal.timeout(8000),
|
|
33
|
+
});
|
|
34
|
+
if (!res.ok)
|
|
35
|
+
return cachedLatest?.version ?? null;
|
|
36
|
+
const data = await res.json();
|
|
37
|
+
const latest = data?.['dist-tags']?.latest;
|
|
38
|
+
if (latest) {
|
|
39
|
+
cachedLatest = { version: latest, ts: Date.now() };
|
|
40
|
+
}
|
|
41
|
+
return latest ?? cachedLatest?.version ?? null;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return cachedLatest?.version ?? null;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export function isNewerVersion(latest, local) {
|
|
48
|
+
const parse = (v) => v.replace(/^v/, '').split('.').map(Number);
|
|
49
|
+
const a = parse(latest);
|
|
50
|
+
const b = parse(local);
|
|
51
|
+
for (let i = 0; i < 3; i++) {
|
|
52
|
+
if ((a[i] || 0) > (b[i] || 0))
|
|
53
|
+
return true;
|
|
54
|
+
if ((a[i] || 0) < (b[i] || 0))
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { getWorkspace } from '../storage/workspace-store.js';
|
|
3
|
+
export async function executeCommandNode(workspaceId, node) {
|
|
4
|
+
const workspace = getWorkspace(workspaceId);
|
|
5
|
+
const cwd = node.data.cwd || workspace?.boundDirs?.[0] || process.cwd();
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
exec(node.data.script, {
|
|
8
|
+
cwd,
|
|
9
|
+
env: { ...process.env, ...node.data.env },
|
|
10
|
+
shell: node.data.shell || undefined,
|
|
11
|
+
timeout: 300_000,
|
|
12
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
13
|
+
}, (error, stdout, stderr) => {
|
|
14
|
+
resolve({
|
|
15
|
+
success: !error,
|
|
16
|
+
exitCode: error ? (typeof error.code === 'number' ? error.code : 1) : 0,
|
|
17
|
+
stdout: stdout || '',
|
|
18
|
+
stderr: stderr || '',
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=workflow-command-runner.js.map
|
|
@@ -72,6 +72,8 @@ function resolveStaleRoles(nodes) {
|
|
|
72
72
|
const agentMap = new Map(listTemplates().map(a => [a.id, a]));
|
|
73
73
|
const invalidIds = [];
|
|
74
74
|
const resolved = nodes.map(node => {
|
|
75
|
+
if (node.type === 'command')
|
|
76
|
+
return node;
|
|
75
77
|
const agent = agentMap.get(node.data.agentConfigId);
|
|
76
78
|
if (!agent) {
|
|
77
79
|
invalidIds.push(node.id);
|
|
@@ -177,19 +179,34 @@ export function mapWorkflowToTaskDrafts(template) {
|
|
|
177
179
|
for (const edge of template.edges) {
|
|
178
180
|
dependsOn.get(edge.target)?.push(edge.source);
|
|
179
181
|
}
|
|
180
|
-
return template.nodes.map(node =>
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
182
|
+
return template.nodes.map(node => {
|
|
183
|
+
if (node.type === 'command') {
|
|
184
|
+
return {
|
|
185
|
+
key: node.id,
|
|
186
|
+
title: node.data.label,
|
|
187
|
+
description: `Run command: ${node.data.label}`,
|
|
188
|
+
agentConfigId: undefined,
|
|
189
|
+
dependsOnKeys: dependsOn.get(node.id)?.length ? dependsOn.get(node.id) : undefined,
|
|
190
|
+
sandboxDirs: undefined,
|
|
191
|
+
commandNode: node,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
key: node.id,
|
|
196
|
+
title: node.data.taskTitleTemplate || node.data.label,
|
|
197
|
+
description: node.data.taskDescriptionTemplate || `Task assigned to ${node.data.label} (${node.data.role})`,
|
|
198
|
+
agentConfigId: node.data.agentConfigId,
|
|
199
|
+
dependsOnKeys: dependsOn.get(node.id)?.length ? dependsOn.get(node.id) : undefined,
|
|
200
|
+
sandboxDirs: undefined,
|
|
201
|
+
};
|
|
202
|
+
});
|
|
188
203
|
}
|
|
189
204
|
// --- Run-time Validation ---
|
|
190
205
|
export function validateWorkflowForRun(_workspaceId, template, memberAgentIds) {
|
|
191
206
|
const agentMap = new Map(listTemplates().map((a) => [a.id, a]));
|
|
192
207
|
for (const node of template.nodes) {
|
|
208
|
+
if (node.type === 'command')
|
|
209
|
+
continue;
|
|
193
210
|
const agent = agentMap.get(node.data.agentConfigId);
|
|
194
211
|
if (!agent)
|
|
195
212
|
return `Agent "${node.data.label}" (${node.data.agentConfigId}) no longer exists`;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { v4 as uuid } from 'uuid';
|
|
2
2
|
import { listWorkspaces, getWorkspace, createWorkspace, updateWorkspace, deleteWorkspace } from '../storage/workspace-store.js';
|
|
3
|
+
import { listWorktrees } from '../storage/worktree-store.js';
|
|
3
4
|
import { ensureDir } from '../storage/json-store.js';
|
|
4
5
|
import { join } from 'node:path';
|
|
5
6
|
import { existsSync, writeFileSync } from 'node:fs';
|
|
@@ -21,7 +22,14 @@ function initAgentspace(agentspaceDir) {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
export function getAll() {
|
|
24
|
-
|
|
25
|
+
const workspaces = listWorkspaces();
|
|
26
|
+
const workspaceIds = new Set(workspaces.map((workspace) => workspace.id));
|
|
27
|
+
const worktreeWorkspaces = workspaces
|
|
28
|
+
.filter((workspace) => !workspace.isWorktree)
|
|
29
|
+
.flatMap((workspace) => listWorktrees(workspace.id)
|
|
30
|
+
.filter((worktree) => worktree.status === 'active' && !workspaceIds.has(worktree.id))
|
|
31
|
+
.map(worktreeToWorkspace));
|
|
32
|
+
return [...workspaces, ...worktreeWorkspaces];
|
|
25
33
|
}
|
|
26
34
|
export function getById(id) {
|
|
27
35
|
return getWorkspace(id);
|
|
@@ -72,4 +80,18 @@ export function remove(id) {
|
|
|
72
80
|
deleteWorkspace(id);
|
|
73
81
|
return true;
|
|
74
82
|
}
|
|
83
|
+
function worktreeToWorkspace(worktree) {
|
|
84
|
+
return {
|
|
85
|
+
id: worktree.id,
|
|
86
|
+
name: `${worktree.name} (Worktree)`,
|
|
87
|
+
boundDirs: [worktree.path],
|
|
88
|
+
agentspaceDir: join(worktree.path, '.agentspace'),
|
|
89
|
+
isWorktree: true,
|
|
90
|
+
parentWorkspaceId: worktree.workspaceId,
|
|
91
|
+
createdAt: worktree.createdAt,
|
|
92
|
+
updatedAt: worktree.updatedAt,
|
|
93
|
+
activeChannels: [],
|
|
94
|
+
activeIssues: [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
75
97
|
//# sourceMappingURL=workspace.js.map
|