@agent-spaces/server 0.3.65 → 0.4.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/dist/adapters/agent-runtime.js +8 -0
- package/dist/adapters/codex-function-tool-bridge.js +152 -0
- package/dist/adapters/codex-runtime.js +23 -4
- package/dist/adapters/git.js +25 -3
- package/dist/adapters/hermes-runtime.js +813 -0
- package/dist/adapters/langchain-runtime.js +384 -21
- package/dist/adapters/oh-my-pi-runtime.js +858 -0
- package/dist/adapters/open-agent-sdk-runtime.js +202 -5
- package/dist/adapters/open-agent-sdk-runtime.test.js +35 -0
- package/dist/agents/agent-message-parts.js +52 -2
- package/dist/agents/issue-task-controller.js +71 -2
- package/dist/agents/pull-request-agent.js +115 -0
- package/dist/agents/scheduler-agent.js +1 -1
- package/dist/agents/title-generator-agent.js +120 -0
- package/dist/app.js +61 -4
- package/dist/middleware/auth.js +1 -1
- package/dist/package.json +2 -1
- package/dist/routes/agent-sse.js +70 -6
- package/dist/routes/channel.js +23 -2
- package/dist/routes/chat-run.js +191 -0
- package/dist/routes/chat.js +142 -0
- package/dist/routes/command.js +16 -0
- package/dist/routes/data.js +189 -0
- package/dist/routes/git.js +10 -1
- package/dist/routes/import.js +199 -0
- package/dist/routes/issue.js +17 -5
- package/dist/routes/notification.js +10 -0
- package/dist/routes/plugin.js +69 -0
- package/dist/routes/version.js +95 -0
- package/dist/routes/workflow-hook.js +71 -0
- package/dist/routes/workflow.js +282 -7
- package/dist/routes/workspace.js +13 -4
- package/dist/routes/worktree.js +93 -0
- package/dist/services/agent.js +123 -36
- package/dist/services/ai-text.js +185 -0
- package/dist/services/builtin-tools/index.js +1 -0
- package/dist/services/builtin-tools/workflow-editor-tools.js +509 -0
- package/dist/services/builtin-tools/workflow-exec-tools.js +320 -0
- package/dist/services/chat.js +134 -0
- package/dist/services/command-process-manager.js +16 -0
- package/dist/services/execution-manager.js +1346 -0
- package/dist/services/generated-title.js +59 -0
- package/dist/services/gitignore.js +22 -18
- package/dist/services/interaction-manager.js +114 -0
- package/dist/services/issue-retry.js +25 -0
- package/dist/services/notification-center.js +9 -0
- package/dist/services/output-style.js +8 -1
- package/dist/services/plugin.js +257 -0
- package/dist/services/prompt-template.js +8 -1
- package/dist/services/pty.js +20 -0
- package/dist/services/search.js +16 -6
- package/dist/services/skill.js +2 -0
- package/dist/services/version.js +69 -0
- package/dist/services/workflow-command-runner.js +24 -0
- package/dist/services/workflow-trigger-service.js +137 -0
- package/dist/services/workflow.js +219 -39
- package/dist/services/workspace.js +23 -1
- package/dist/services/worktree.js +207 -0
- package/dist/storage/agent-store.js +8 -0
- package/dist/storage/chat-store.js +151 -0
- package/dist/storage/database-store.js +6 -0
- package/dist/storage/json-store.js +2 -1
- package/dist/storage/kanban-store.js +6 -0
- package/dist/storage/workflow-store.js +386 -22
- 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 +36 -3
- package/dist/ws/agent-runner.js +30 -18
- package/dist/ws/chat-handler.js +89 -0
- package/dist/ws/connection-manager.js +49 -2
- package/dist/ws/execution-channels.js +88 -0
- package/dist/ws/handler.js +32 -5
- package/dist/ws/message-parts.js +130 -12
- package/dist/ws/terminal-handler.js +26 -0
- package/package.json +13 -1
- package/public/avatars/user.jpg +0 -0
- 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,142 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import * as svc from '../services/chat.js';
|
|
3
|
+
import * as fileService from '../services/file.js';
|
|
4
|
+
const router = Router();
|
|
5
|
+
// GET /api/chat/agents — list all chat agents
|
|
6
|
+
router.get('/agents', (_req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
res.json(svc.listAgents());
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
res.status(500).json({ error: error.message });
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
// POST /api/chat/agents — create agent (requires name, provider, model, apiKey)
|
|
15
|
+
router.post('/agents', (req, res) => {
|
|
16
|
+
const body = req.body;
|
|
17
|
+
const name = typeof body.name === 'string' ? body.name.trim() : '';
|
|
18
|
+
const provider = stringValue(body.provider) || stringValue(body.modelProvider);
|
|
19
|
+
const model = stringValue(body.model) || stringValue(body.modelId);
|
|
20
|
+
if (!name || !provider || !model) {
|
|
21
|
+
res.status(400).json({ error: 'name, provider, and model are required' });
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const agent = svc.createAgent(body);
|
|
26
|
+
res.status(201).json(agent);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
res.status(500).json({ error: error.message });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
// PUT /api/chat/agents/:id — update agent
|
|
33
|
+
router.put('/agents/:id', (req, res) => {
|
|
34
|
+
const { id } = req.params;
|
|
35
|
+
if (!id) {
|
|
36
|
+
res.status(400).json({ error: 'id is required' });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const patch = normalizeChatAgentPatch(req.body);
|
|
41
|
+
const agent = svc.updateAgent(id, patch);
|
|
42
|
+
if (!agent) {
|
|
43
|
+
res.status(404).json({ error: 'Agent not found' });
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
res.json(agent);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
res.status(500).json({ error: error.message });
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
function normalizeChatAgentPatch(body) {
|
|
53
|
+
if (!body || typeof body !== 'object' || Array.isArray(body))
|
|
54
|
+
return {};
|
|
55
|
+
const patch = { ...body };
|
|
56
|
+
if (!patch.baseURL && patch.apiBase) {
|
|
57
|
+
patch.baseURL = patch.apiBase;
|
|
58
|
+
}
|
|
59
|
+
delete patch.apiBase;
|
|
60
|
+
return patch;
|
|
61
|
+
}
|
|
62
|
+
// DELETE /api/chat/agents/:id — delete agent + its messages
|
|
63
|
+
router.delete('/agents/:id', (req, res) => {
|
|
64
|
+
const { id } = req.params;
|
|
65
|
+
if (!id) {
|
|
66
|
+
res.status(400).json({ error: 'id is required' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const deleted = svc.deleteAgent(id);
|
|
71
|
+
if (!deleted) {
|
|
72
|
+
res.status(404).json({ error: 'Agent not found' });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
res.status(204).send();
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
res.status(500).json({ error: error.message });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
// GET /api/chat/agents/:id/messages — list messages (?limit=50&before=msgId)
|
|
82
|
+
router.get('/agents/:id/messages', (req, res) => {
|
|
83
|
+
const { id } = req.params;
|
|
84
|
+
if (!id) {
|
|
85
|
+
res.status(400).json({ error: 'id is required' });
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const agent = svc.findAgent(id);
|
|
90
|
+
if (!agent) {
|
|
91
|
+
res.status(404).json({ error: 'Agent not found' });
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const limit = req.query.limit ? parseInt(req.query.limit, 10) : undefined;
|
|
95
|
+
const before = req.query.before;
|
|
96
|
+
res.json(svc.listMessages(id, limit, before));
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
res.status(500).json({ error: error.message });
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// DELETE /api/chat/agents/:id/messages — clear messages
|
|
103
|
+
router.delete('/agents/:id/messages', (req, res) => {
|
|
104
|
+
const { id } = req.params;
|
|
105
|
+
if (!id) {
|
|
106
|
+
res.status(400).json({ error: 'id is required' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
try {
|
|
110
|
+
svc.clearMessages(id);
|
|
111
|
+
res.status(204).send();
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
res.status(500).json({ error: error.message });
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
// GET /api/chat/agents/:id/workspace/tree - read chat agent working directory
|
|
118
|
+
router.get('/agents/:id/workspace/tree', async (req, res) => {
|
|
119
|
+
const { id } = req.params;
|
|
120
|
+
if (!id) {
|
|
121
|
+
res.status(400).json({ error: 'id is required' });
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
const workspace = svc.getAgentWorkspace(id);
|
|
126
|
+
if (!workspace) {
|
|
127
|
+
res.status(404).json({ error: 'Agent workspace not found' });
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const relPath = typeof req.query.path === 'string' ? req.query.path : '';
|
|
131
|
+
const depth = req.query.depth ? Number(req.query.depth) : Infinity;
|
|
132
|
+
res.json(await fileService.readTree(workspace, relPath, depth));
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
res.status(500).json({ error: error.message });
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
function stringValue(value) {
|
|
139
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
140
|
+
}
|
|
141
|
+
export default router;
|
|
142
|
+
//# sourceMappingURL=chat.js.map
|
package/dist/routes/command.js
CHANGED
|
@@ -104,5 +104,21 @@ router.post('/:commandId/stop', (req, res) => {
|
|
|
104
104
|
res.status(400).json({ error: error.message });
|
|
105
105
|
}
|
|
106
106
|
});
|
|
107
|
+
router.post('/:commandId/restart', (req, res) => {
|
|
108
|
+
const { id: workspaceId, commandId } = req.params;
|
|
109
|
+
if (!workspaceId || !commandId) {
|
|
110
|
+
res.status(400).json({ error: 'workspaceId and commandId required' });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
try {
|
|
114
|
+
const sessionId = processManager.restartCommand(workspaceId, commandId);
|
|
115
|
+
console.log(`[command] POST restart: workspace=${workspaceId} command=${commandId} -> session=${sessionId}`);
|
|
116
|
+
res.json({ sessionId });
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
console.error(`[command] POST restart error: workspace=${workspaceId} command=${commandId}`, error.message);
|
|
120
|
+
res.status(400).json({ error: error.message });
|
|
121
|
+
}
|
|
122
|
+
});
|
|
107
123
|
export default router;
|
|
108
124
|
//# sourceMappingURL=command.js.map
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { existsSync, statSync, rmSync, cpSync, readdirSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { tmpdir } from 'node:os';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import archiver from 'archiver';
|
|
7
|
+
import AdmZip from 'adm-zip';
|
|
8
|
+
import multer from 'multer';
|
|
9
|
+
import { getDataDir } from '../storage/json-store.js';
|
|
10
|
+
import * as agentStore from '../storage/agent-store.js';
|
|
11
|
+
import * as databaseStore from '../storage/database-store.js';
|
|
12
|
+
import * as kanbanStore from '../storage/kanban-store.js';
|
|
13
|
+
const router = Router();
|
|
14
|
+
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 500 * 1024 * 1024 } });
|
|
15
|
+
const CATEGORIES = {
|
|
16
|
+
'auth': { path: 'auth.json', label: 'Authentication', group: 'config' },
|
|
17
|
+
'user-settings': { path: 'user-settings.json', label: 'User Settings', group: 'config' },
|
|
18
|
+
'robot-accounts': { path: 'robot-accounts.json', label: 'Robot Accounts', group: 'config' },
|
|
19
|
+
'speech-recognition': { path: 'speech-recognition.json', label: 'Speech Recognition', group: 'config' },
|
|
20
|
+
'llm': { path: 'llm', label: 'LLM Models & Providers', group: 'ai' },
|
|
21
|
+
'agents': { path: 'agents', label: 'Agent Usage', group: 'content' },
|
|
22
|
+
'database': { path: 'database', label: 'Document Database', group: 'content' },
|
|
23
|
+
'kanban': { path: 'kanban', label: 'Kanban Boards', group: 'content' },
|
|
24
|
+
'output-styles': { path: 'output-styles', label: 'Output Styles', group: 'customization' },
|
|
25
|
+
'prompt-templates': { path: 'prompt-templates', label: 'Prompt Templates', group: 'customization' },
|
|
26
|
+
'subscriptions': { path: 'subscriptions', label: 'Subscriptions', group: 'billing' },
|
|
27
|
+
'skills': { path: 'skills', label: 'Skills', group: 'customization' },
|
|
28
|
+
'mcps': { path: 'mcps', label: 'MCP Servers', group: 'customization' },
|
|
29
|
+
'agent-templates': { path: 'agent-templates', label: 'Agent Templates', group: 'customization' },
|
|
30
|
+
'workflows': { path: 'workflows', label: 'Workflows', group: 'content' },
|
|
31
|
+
};
|
|
32
|
+
// GET /api/data/export — stream zip backup
|
|
33
|
+
router.get('/export', (_req, res) => {
|
|
34
|
+
const dataDir = getDataDir();
|
|
35
|
+
const timestamp = new Date().toISOString().slice(0, 10);
|
|
36
|
+
res.setHeader('Content-Type', 'application/zip');
|
|
37
|
+
res.setHeader('Content-Disposition', `attachment; filename="agent-spaces-backup-${timestamp}.zip"`);
|
|
38
|
+
const archive = archiver('zip', { zlib: { level: 6 } });
|
|
39
|
+
archive.on('error', (err) => {
|
|
40
|
+
console.error('[data-export] archive error:', err);
|
|
41
|
+
if (!res.headersSent) {
|
|
42
|
+
res.status(500).json({ error: 'Failed to create archive' });
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
res.end();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
archive.pipe(res);
|
|
49
|
+
for (const { path: relPath } of Object.values(CATEGORIES)) {
|
|
50
|
+
const fullPath = join(dataDir, relPath);
|
|
51
|
+
if (!existsSync(fullPath))
|
|
52
|
+
continue;
|
|
53
|
+
const stat = statSync(fullPath);
|
|
54
|
+
if (stat.isDirectory()) {
|
|
55
|
+
archive.directory(fullPath, relPath);
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
archive.file(fullPath, { name: relPath });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
archive.finalize();
|
|
62
|
+
});
|
|
63
|
+
// POST /api/data/import/preview — upload zip, extract, return categories
|
|
64
|
+
router.post('/import/preview', upload.single('file'), (req, res) => {
|
|
65
|
+
if (!req.file?.buffer) {
|
|
66
|
+
res.status(400).json({ error: 'No file uploaded' });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const zip = new AdmZip(req.file.buffer);
|
|
71
|
+
const sessionId = randomUUID();
|
|
72
|
+
const tempDir = join(tmpdir(), `agent-spaces-import-${sessionId}`);
|
|
73
|
+
zip.extractAllTo(tempDir, true);
|
|
74
|
+
const found = [];
|
|
75
|
+
for (const [key, { path: relPath, label, group }] of Object.entries(CATEGORIES)) {
|
|
76
|
+
const fullPath = join(tempDir, relPath);
|
|
77
|
+
if (!existsSync(fullPath))
|
|
78
|
+
continue;
|
|
79
|
+
const stat = statSync(fullPath);
|
|
80
|
+
const isDir = stat.isDirectory();
|
|
81
|
+
found.push({
|
|
82
|
+
key,
|
|
83
|
+
label,
|
|
84
|
+
group,
|
|
85
|
+
size: isDir ? getDirSize(fullPath) : stat.size,
|
|
86
|
+
type: isDir ? 'directory' : 'file',
|
|
87
|
+
details: isDir ? `${countFiles(fullPath)} files` : formatSize(stat.size),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
activeImportSessions.set(sessionId, { tempDir, expiresAt: Date.now() + 30 * 60 * 1000 });
|
|
91
|
+
res.json({ sessionId, categories: found });
|
|
92
|
+
}
|
|
93
|
+
catch (e) {
|
|
94
|
+
res.status(500).json({ error: e.message });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
// POST /api/data/import/execute — restore selected categories
|
|
98
|
+
router.post('/import/execute', (req, res) => {
|
|
99
|
+
const { sessionId, categories: selectedCategories } = req.body;
|
|
100
|
+
if (!sessionId || !selectedCategories?.length) {
|
|
101
|
+
res.status(400).json({ error: 'sessionId and categories are required' });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const session = activeImportSessions.get(sessionId);
|
|
105
|
+
if (!session || Date.now() > session.expiresAt) {
|
|
106
|
+
res.status(410).json({ error: 'Import session expired. Please upload again.' });
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const dataDir = getDataDir();
|
|
110
|
+
const results = {};
|
|
111
|
+
for (const categoryKey of selectedCategories) {
|
|
112
|
+
const category = CATEGORIES[categoryKey];
|
|
113
|
+
if (!category) {
|
|
114
|
+
results[categoryKey] = 'skipped';
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
const srcPath = join(session.tempDir, category.path);
|
|
119
|
+
const destPath = join(dataDir, category.path);
|
|
120
|
+
if (!existsSync(srcPath)) {
|
|
121
|
+
results[categoryKey] = 'skipped';
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// Close SQLite connections before overwriting
|
|
125
|
+
if (categoryKey === 'agents')
|
|
126
|
+
agentStore.closeDb();
|
|
127
|
+
else if (categoryKey === 'database')
|
|
128
|
+
databaseStore.closeDb();
|
|
129
|
+
else if (categoryKey === 'kanban')
|
|
130
|
+
kanbanStore.closeDb();
|
|
131
|
+
if (statSync(srcPath).isDirectory()) {
|
|
132
|
+
if (existsSync(destPath))
|
|
133
|
+
rmSync(destPath, { recursive: true, force: true });
|
|
134
|
+
cpSync(srcPath, destPath, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
cpSync(srcPath, destPath);
|
|
138
|
+
}
|
|
139
|
+
results[categoryKey] = 'ok';
|
|
140
|
+
}
|
|
141
|
+
catch (e) {
|
|
142
|
+
console.error(`[data-import] error importing ${categoryKey}:`, e);
|
|
143
|
+
results[categoryKey] = 'error';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Cleanup
|
|
147
|
+
rmSync(session.tempDir, { recursive: true, force: true });
|
|
148
|
+
activeImportSessions.delete(sessionId);
|
|
149
|
+
res.json({ results });
|
|
150
|
+
});
|
|
151
|
+
// --- In-memory import sessions with auto-cleanup ---
|
|
152
|
+
const activeImportSessions = new Map();
|
|
153
|
+
setInterval(() => {
|
|
154
|
+
const now = Date.now();
|
|
155
|
+
for (const [id, session] of activeImportSessions) {
|
|
156
|
+
if (now > session.expiresAt) {
|
|
157
|
+
rmSync(session.tempDir, { recursive: true, force: true });
|
|
158
|
+
activeImportSessions.delete(id);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}, 10 * 60 * 1000).unref();
|
|
162
|
+
// --- Helpers ---
|
|
163
|
+
function listFilesRecursive(dir) {
|
|
164
|
+
const results = [];
|
|
165
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
166
|
+
if (entry.isDirectory()) {
|
|
167
|
+
results.push(...listFilesRecursive(join(dir, entry.name)));
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
results.push(join(dir, entry.name));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return results;
|
|
174
|
+
}
|
|
175
|
+
function getDirSize(dir) {
|
|
176
|
+
return listFilesRecursive(dir).reduce((sum, f) => sum + statSync(f).size, 0);
|
|
177
|
+
}
|
|
178
|
+
function countFiles(dir) {
|
|
179
|
+
return listFilesRecursive(dir).length;
|
|
180
|
+
}
|
|
181
|
+
function formatSize(bytes) {
|
|
182
|
+
if (bytes < 1024)
|
|
183
|
+
return `${bytes} B`;
|
|
184
|
+
if (bytes < 1024 * 1024)
|
|
185
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
186
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
187
|
+
}
|
|
188
|
+
export default router;
|
|
189
|
+
//# sourceMappingURL=data.js.map
|
package/dist/routes/git.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
|
-
import { gitStatus, gitDiff, gitLog, gitCommit, gitDiscard, gitDiscardAll, gitBranches, gitCheckout, gitInit, gitGenerateCommitMsg, gitPush, gitPull, gitFetch, gitGetRemotes, gitAddRemote, gitCheckoutDetached, gitCherryPick, gitCreateBranch, gitDeleteBranch, gitCreateTag, gitCommitDiff, gitGetRemoteUrl, gitMergeBase, gitGetConfig, gitSetConfig, gitStage, gitUnstage, gitResolveFile } from '../adapters/git.js';
|
|
2
|
+
import { gitStatus, gitDiff, gitLog, gitCommit, gitDiscard, gitDiscardAll, gitBranches, gitCheckout, gitInit, gitGenerateCommitMsg, gitPush, gitPull, gitFetch, gitGetRemotes, gitAddRemote, gitCheckoutDetached, gitCherryPick, gitCreateBranch, gitDeleteBranch, gitCreateTag, gitCommitDiff, gitGetRemoteUrl, gitMergeBase, gitGetConfig, gitSetConfig, gitStage, gitUnstage, gitResolveFile, gitReset } from '../adapters/git.js';
|
|
3
3
|
import { logGitOperation, getGitOperations } from '../services/git-operation-log.js';
|
|
4
4
|
const router = Router({ mergeParams: true });
|
|
5
5
|
function withLog(operation, inputFn, handler) {
|
|
@@ -201,5 +201,14 @@ router.post('/config', withLog('config.set', (req) => ({ name: req.body?.name, e
|
|
|
201
201
|
router.get('/operations', (req, res) => {
|
|
202
202
|
res.json(getGitOperations(req.params.id));
|
|
203
203
|
});
|
|
204
|
+
router.post('/reset', withLog('reset', (req) => ({ commitHash: req.body?.commitHash, mode: req.body?.mode }), async (req, res) => {
|
|
205
|
+
const { commitHash, mode } = req.body;
|
|
206
|
+
if (!commitHash) {
|
|
207
|
+
res.status(400).json({ error: 'commitHash is required' });
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
await gitReset(req.params.id, commitHash, mode || 'mixed');
|
|
211
|
+
res.json({ ok: true });
|
|
212
|
+
}));
|
|
204
213
|
export default router;
|
|
205
214
|
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import * as llmStore from '../storage/llm-store.js';
|
|
6
|
+
import { importSkillsBatch } from '../services/skill.js';
|
|
7
|
+
import { importMcps } from '../services/mcp.js';
|
|
8
|
+
const router = Router();
|
|
9
|
+
const CC_SWITCH_DIR = join(homedir(), '.cc-switch');
|
|
10
|
+
const CONFIG_FILE = join(CC_SWITCH_DIR, 'config.json.migrated');
|
|
11
|
+
const SKILLS_DIR = join(CC_SWITCH_DIR, 'skills');
|
|
12
|
+
const MODEL_ENV_KEYS = [
|
|
13
|
+
'ANTHROPIC_MODEL',
|
|
14
|
+
'ANTHROPIC_DEFAULT_HAIKU_MODEL',
|
|
15
|
+
'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
|
16
|
+
'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
|
17
|
+
];
|
|
18
|
+
function extractModels(env) {
|
|
19
|
+
const seen = new Set();
|
|
20
|
+
for (const key of MODEL_ENV_KEYS) {
|
|
21
|
+
const val = env[key];
|
|
22
|
+
if (val && !seen.has(val))
|
|
23
|
+
seen.add(val);
|
|
24
|
+
}
|
|
25
|
+
return [...seen];
|
|
26
|
+
}
|
|
27
|
+
function parseProviders(config) {
|
|
28
|
+
const results = [];
|
|
29
|
+
const sections = ['claude', 'codex', 'gemini'];
|
|
30
|
+
const envMappings = {
|
|
31
|
+
claude: { base: 'ANTHROPIC_BASE_URL', key: 'ANTHROPIC_AUTH_TOKEN' },
|
|
32
|
+
codex: { base: 'CODEX_BASE_URL', key: 'OPENAI_API_KEY' },
|
|
33
|
+
gemini: { base: 'GOOGLE_GEMINI_BASE_URL', key: 'GEMINI_API_KEY' },
|
|
34
|
+
};
|
|
35
|
+
for (const section of sections) {
|
|
36
|
+
const providers = config[section]?.providers;
|
|
37
|
+
if (!providers)
|
|
38
|
+
continue;
|
|
39
|
+
const { base: baseKey, key: apiKeyKey } = envMappings[section];
|
|
40
|
+
for (const [id, p] of Object.entries(providers)) {
|
|
41
|
+
const env = p.settingsConfig?.env || {};
|
|
42
|
+
let apiBase = env[baseKey] || '';
|
|
43
|
+
let apiKey = env[apiKeyKey] || '';
|
|
44
|
+
if (section === 'codex') {
|
|
45
|
+
apiKey = apiKey || p.settingsConfig?.auth?.OPENAI_API_KEY || '';
|
|
46
|
+
if (!apiBase) {
|
|
47
|
+
const configStr = p.settingsConfig?.config || '';
|
|
48
|
+
const match = configStr.match(/base_url\s*=\s*"([^"]+)"/);
|
|
49
|
+
if (match)
|
|
50
|
+
apiBase = match[1];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (section === 'claude') {
|
|
54
|
+
apiKey = apiKey || env.ANTHROPIC_API_KEY || '';
|
|
55
|
+
}
|
|
56
|
+
if (!apiKey && !apiBase)
|
|
57
|
+
continue;
|
|
58
|
+
results.push({
|
|
59
|
+
sourceId: id,
|
|
60
|
+
name: p.name || id,
|
|
61
|
+
apiBase,
|
|
62
|
+
apiKey,
|
|
63
|
+
source: section,
|
|
64
|
+
websiteUrl: p.websiteUrl,
|
|
65
|
+
category: p.category,
|
|
66
|
+
models: extractModels(env),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return results;
|
|
71
|
+
}
|
|
72
|
+
function parseSkills() {
|
|
73
|
+
if (!existsSync(SKILLS_DIR))
|
|
74
|
+
return [];
|
|
75
|
+
const results = [];
|
|
76
|
+
const folders = readdirSync(SKILLS_DIR).filter(f => {
|
|
77
|
+
const p = join(SKILLS_DIR, f);
|
|
78
|
+
return statSync(p).isDirectory() && !f.startsWith('_');
|
|
79
|
+
});
|
|
80
|
+
for (const folder of folders) {
|
|
81
|
+
const skillFile = join(SKILLS_DIR, folder, 'SKILL.md');
|
|
82
|
+
if (!existsSync(skillFile))
|
|
83
|
+
continue;
|
|
84
|
+
const content = readFileSync(skillFile, 'utf-8');
|
|
85
|
+
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
86
|
+
let description = '';
|
|
87
|
+
if (fmMatch) {
|
|
88
|
+
const descMatch = fmMatch[1].match(/description:\s*["']?(.+?)["']?\s*$/m);
|
|
89
|
+
if (descMatch)
|
|
90
|
+
description = descMatch[1];
|
|
91
|
+
}
|
|
92
|
+
results.push({ name: folder, path: skillFile, description });
|
|
93
|
+
}
|
|
94
|
+
return results;
|
|
95
|
+
}
|
|
96
|
+
function parseMcps(config) {
|
|
97
|
+
const servers = config.mcp?.servers;
|
|
98
|
+
if (!servers)
|
|
99
|
+
return [];
|
|
100
|
+
const results = [];
|
|
101
|
+
for (const [, s] of Object.entries(servers)) {
|
|
102
|
+
if (!s.server?.command)
|
|
103
|
+
continue;
|
|
104
|
+
results.push({
|
|
105
|
+
name: s.name || s.id,
|
|
106
|
+
command: s.server.command,
|
|
107
|
+
args: s.server.args || [],
|
|
108
|
+
env: s.server.env || {},
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return results;
|
|
112
|
+
}
|
|
113
|
+
// GET /api/import/cc-switch/preview
|
|
114
|
+
router.get('/cc-switch/preview', (_req, res) => {
|
|
115
|
+
if (!existsSync(CONFIG_FILE)) {
|
|
116
|
+
res.json({ providers: [], skills: [], mcps: [], error: 'cc-switch config not found' });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const raw = readFileSync(CONFIG_FILE, 'utf-8');
|
|
121
|
+
const config = JSON.parse(raw);
|
|
122
|
+
const providers = parseProviders(config);
|
|
123
|
+
const skills = parseSkills();
|
|
124
|
+
const mcps = parseMcps(config);
|
|
125
|
+
res.json({ providers, skills, mcps });
|
|
126
|
+
}
|
|
127
|
+
catch (e) {
|
|
128
|
+
res.status(500).json({ error: e.message });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// POST /api/import/cc-switch/execute
|
|
132
|
+
router.post('/cc-switch/execute', (req, res) => {
|
|
133
|
+
const { providers: selectedProviders, skills: selectedSkills, mcps: selectedMcps } = req.body;
|
|
134
|
+
const results = { providers: [], models: [], skills: [], mcps: [] };
|
|
135
|
+
// Import providers + models
|
|
136
|
+
if (selectedProviders?.length) {
|
|
137
|
+
const existingProviders = llmStore.listProviders();
|
|
138
|
+
const existingModels = llmStore.listModels();
|
|
139
|
+
for (const p of selectedProviders) {
|
|
140
|
+
if (!p.name)
|
|
141
|
+
continue;
|
|
142
|
+
// skip if provider with same name already exists
|
|
143
|
+
let provider = existingProviders.find(ep => ep.name === p.name);
|
|
144
|
+
if (!provider) {
|
|
145
|
+
provider = llmStore.createProvider({
|
|
146
|
+
name: p.name,
|
|
147
|
+
apiBase: p.apiBase || '',
|
|
148
|
+
apiKey: p.apiKey || '',
|
|
149
|
+
});
|
|
150
|
+
results.providers.push(p.name);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
results.providers.push(`${p.name} (skipped: exists)`);
|
|
154
|
+
}
|
|
155
|
+
// import associated models (deduplicated)
|
|
156
|
+
for (const modelId of p.models) {
|
|
157
|
+
if (existingModels.some(m => m.modelId === modelId && m.provider === provider.id))
|
|
158
|
+
continue;
|
|
159
|
+
llmStore.createModel({
|
|
160
|
+
modelId,
|
|
161
|
+
name: modelId,
|
|
162
|
+
provider: provider.id,
|
|
163
|
+
thinkingEnabled: true,
|
|
164
|
+
thinkingEffort: 'medium',
|
|
165
|
+
vision: false,
|
|
166
|
+
reasoning: false,
|
|
167
|
+
embedding: false,
|
|
168
|
+
});
|
|
169
|
+
results.models.push(modelId);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Import skills
|
|
174
|
+
if (selectedSkills?.length) {
|
|
175
|
+
const items = [];
|
|
176
|
+
for (const s of selectedSkills) {
|
|
177
|
+
const skillFile = join(SKILLS_DIR, s.name, 'SKILL.md');
|
|
178
|
+
if (!existsSync(skillFile))
|
|
179
|
+
continue;
|
|
180
|
+
items.push({ name: s.name, content: readFileSync(skillFile, 'utf-8') });
|
|
181
|
+
}
|
|
182
|
+
if (items.length) {
|
|
183
|
+
const imported = importSkillsBatch(items);
|
|
184
|
+
results.skills = imported.map(s => s.name);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Import MCP servers
|
|
188
|
+
if (selectedMcps?.length) {
|
|
189
|
+
const mcpServers = {};
|
|
190
|
+
for (const m of selectedMcps) {
|
|
191
|
+
mcpServers[m.name] = { command: m.command, args: m.args, env: m.env };
|
|
192
|
+
}
|
|
193
|
+
const imported = importMcps(JSON.stringify(mcpServers));
|
|
194
|
+
results.mcps = imported.map(m => m.name);
|
|
195
|
+
}
|
|
196
|
+
res.json(results);
|
|
197
|
+
});
|
|
198
|
+
export default router;
|
|
199
|
+
//# sourceMappingURL=import.js.map
|
package/dist/routes/issue.js
CHANGED
|
@@ -10,6 +10,7 @@ import { retryIssue } from '../services/issue-retry.js';
|
|
|
10
10
|
import { hasActiveIssueAutomation, runIssueAutomation } from '../agents/issue-agent-runner.js';
|
|
11
11
|
import { continueIssueTaskScheduling, stopIssueAutomation } from '../agents/issue-task-controller.js';
|
|
12
12
|
import * as workflowService from '../services/workflow.js';
|
|
13
|
+
import { scheduleIssueTitleGeneration } from '../services/generated-title.js';
|
|
13
14
|
const router = Router({ mergeParams: true });
|
|
14
15
|
router.get('/', (req, res) => {
|
|
15
16
|
const status = req.query.status;
|
|
@@ -18,13 +19,15 @@ router.get('/', (req, res) => {
|
|
|
18
19
|
});
|
|
19
20
|
router.post('/', (req, res) => {
|
|
20
21
|
const { title, description, members, workflowId } = req.body;
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
const trimmedTitle = typeof title === 'string' ? title.trim() : '';
|
|
23
|
+
const trimmedDescription = typeof description === 'string' ? description.trim() : '';
|
|
24
|
+
if (!trimmedTitle && !trimmedDescription) {
|
|
25
|
+
res.status(400).json({ error: 'title or description is required' });
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
25
28
|
const issue = issueService.create(req.params.id, {
|
|
26
|
-
title,
|
|
27
|
-
description:
|
|
29
|
+
title: trimmedTitle,
|
|
30
|
+
description: trimmedDescription,
|
|
28
31
|
members: mergeWorkflowMembers(members, workflowId),
|
|
29
32
|
workflowId,
|
|
30
33
|
});
|
|
@@ -33,6 +36,15 @@ router.post('/', (req, res) => {
|
|
|
33
36
|
broadcastToWorkspace(req.params.id, 'channel.updated', channel);
|
|
34
37
|
broadcastToWorkspace(req.params.id, 'issue.created', issue);
|
|
35
38
|
res.status(201).json(issue);
|
|
39
|
+
if (!trimmedTitle) {
|
|
40
|
+
scheduleIssueTitleGeneration({
|
|
41
|
+
workspaceId: req.params.id,
|
|
42
|
+
issueId: issue.id,
|
|
43
|
+
requirement: trimmedDescription,
|
|
44
|
+
description: trimmedDescription,
|
|
45
|
+
broadcast: (event, data) => broadcastToWorkspace(req.params.id, event, data),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
36
48
|
});
|
|
37
49
|
router.get('/:issueId', (req, res) => {
|
|
38
50
|
const issue = issueService.getById(req.params.id, req.params.issueId);
|
|
@@ -313,7 +325,7 @@ function mergeWorkflowMembers(members, workflowId) {
|
|
|
313
325
|
return base;
|
|
314
326
|
return Array.from(new Set([
|
|
315
327
|
...base,
|
|
316
|
-
...workflow.nodes.map((node) => node.data.agentConfigId).filter(Boolean),
|
|
328
|
+
...workflow.nodes.filter((n) => n.type === 'agent').map((node) => node.data.agentConfigId).filter(Boolean),
|
|
317
329
|
]));
|
|
318
330
|
}
|
|
319
331
|
//# 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
|