@agent-spaces/server 0.3.63 → 0.3.64
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/message-format.js +1 -1
- package/dist/adapters/git.js +161 -57
- package/dist/agents/agent-designer.js +66 -12
- package/dist/agents/issue-task-controller.js +1 -1
- package/dist/app.js +50 -1
- package/dist/package.json +1 -1
- package/dist/routes/agent-commands.js +72 -0
- package/dist/routes/agent-sse.js +6 -0
- package/dist/routes/agent.js +15 -1
- package/dist/routes/database.js +345 -0
- package/dist/routes/git.js +52 -1
- package/dist/routes/kanban.js +39 -0
- package/dist/services/agent-commands.js +168 -0
- package/dist/services/builtin-tools/command-tools.js +117 -0
- package/dist/services/builtin-tools/database-tools.js +578 -0
- package/dist/services/builtin-tools/index.js +5 -0
- package/dist/services/builtin-tools/input-helpers.js +26 -0
- package/dist/services/builtin-tools/issue-tools.js +209 -0
- package/dist/services/builtin-tools/kanban-tools.js +277 -0
- package/dist/services/database-vector.js +244 -0
- package/dist/services/kanban.js +50 -0
- package/dist/storage/database-store.js +365 -0
- package/dist/storage/kanban-store.js +142 -0
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +4 -4
- package/dist/web/__next._full.txt +24 -29
- package/dist/web/__next._head.txt +4 -4
- package/dist/web/__next._index.txt +14 -14
- package/dist/web/__next._tree.txt +3 -8
- package/dist/web/_next/static/chunks/0-9194nbxy_6d.js +1 -0
- package/dist/web/_next/static/chunks/{13~y-b.b9rrw4.js → 01~quun6sefgl.js} +1 -1
- package/dist/web/_next/static/chunks/04a4vsq2wknm4.js +1 -0
- package/dist/web/_next/static/chunks/04dg4l4hv11q2.js +3 -0
- package/dist/web/_next/static/chunks/04fxddw-y20~-.js +7 -0
- package/dist/web/_next/static/chunks/04w7~5ooz_pwm.js +1 -0
- package/dist/web/_next/static/chunks/05oc21sj24wtq.js +1 -0
- package/dist/web/_next/static/chunks/{0-oog4zg4_m~m.css → 062f9zqctzg.b.css} +0 -3
- package/dist/web/_next/static/chunks/{014x2qbuiszni.js → 08ckpwmmwlors.js} +3 -3
- package/dist/web/_next/static/chunks/08k~meqbd8d6v.js +1 -0
- package/dist/web/_next/static/chunks/099h96wjsdb25.js +2 -0
- package/dist/web/_next/static/chunks/09h23logvq65m.js +1 -0
- package/dist/web/_next/static/chunks/0_mvduwjsm35w.js +1 -0
- package/dist/web/_next/static/chunks/0a5y-vhf4i5id.js +3 -0
- package/dist/web/_next/static/chunks/0ake2f3x2uan4.js +24 -0
- package/dist/web/_next/static/chunks/0ck8dw_9-1cdx.js +1 -0
- package/dist/web/_next/static/chunks/0f7cb9li~3jra.js +67 -0
- package/dist/web/_next/static/chunks/0fttswpzu69qx.js +1 -0
- package/dist/web/_next/static/chunks/0ghs9on7wodrm.js +1 -0
- package/dist/web/_next/static/chunks/0ghx3j_.-gdyd.js +1 -0
- package/dist/web/_next/static/chunks/0h9cu-k6z5o08.js +1 -0
- package/dist/web/_next/static/chunks/{02c22g~xd-y30.js → 0iuf30t0rjsjv.js} +2 -2
- package/dist/web/_next/static/chunks/{046me66nilkff.js → 0jb4~3qqkw2ps.js} +1 -1
- package/dist/web/_next/static/chunks/0k4zdm72k_bfy.js +1 -0
- package/dist/web/_next/static/chunks/{0kof5qdg8c2-k.js → 0n6_4so_afuwk.js} +37 -37
- package/dist/web/_next/static/chunks/0nb8.iteznuvx.js +1 -0
- package/dist/web/_next/static/chunks/0os58q93stt7j.js +3 -0
- package/dist/web/_next/static/chunks/0s9lmk8iauou3.js +1 -0
- package/dist/web/_next/static/chunks/0sp_zbx~w0am7.js +1 -0
- package/dist/web/_next/static/chunks/0tel~zsv4z8l_.js +1 -0
- package/dist/web/_next/static/chunks/0twamv4wr_dbv.js +1 -0
- package/dist/web/_next/static/chunks/{0_udc.6.tueey.js → 0uhol5wafdbl~.js} +1 -1
- package/dist/web/_next/static/chunks/0v3a_x4vt42kx.js +5 -0
- package/dist/web/_next/static/chunks/{002-dxhags4dj.js → 0v6hte2z-32ca.js} +2 -2
- package/dist/web/_next/static/chunks/0v7q4mys.mnm..css +1 -0
- package/dist/web/_next/static/chunks/{0ogpc3f3keopc.js → 0vbqaynjq8ga..js} +2 -2
- package/dist/web/_next/static/chunks/0xbaakj0dfc0..js +1 -0
- package/dist/web/_next/static/chunks/0z~vqzbm_q371.js +1 -0
- package/dist/web/_next/static/chunks/0~3xm80~j9ddg.js +1 -0
- package/dist/web/_next/static/chunks/{0y09i51u6ixq5.js → 10l-9myrdo3x9.js} +1 -1
- package/dist/web/_next/static/chunks/12jm4gwmvq-0q.js +90 -0
- package/dist/web/_next/static/chunks/{0aa6bcdmtpekn.js → 1442stwa0gbxe.js} +1 -1
- package/dist/web/_next/static/chunks/14s37n6h0_q3x.js +16 -0
- package/dist/web/_next/static/chunks/161ik5kfyuwtd.js +1 -0
- package/dist/web/_next/static/chunks/17k~zbv0_4rep.js +1 -0
- package/dist/web/_not-found/__next._full.txt +23 -23
- package/dist/web/_not-found/__next._head.txt +4 -4
- package/dist/web/_not-found/__next._index.txt +14 -14
- 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 +3 -3
- package/dist/web/_not-found.html +1 -1
- package/dist/web/_not-found.txt +23 -23
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +24 -29
- package/dist/web/login/__next._full.txt +32 -36
- package/dist/web/login/__next._head.txt +4 -4
- package/dist/web/login/__next._index.txt +14 -14
- package/dist/web/login/__next._tree.txt +3 -8
- 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 +32 -36
- package/dist/web/settings/__next._full.txt +26 -31
- package/dist/web/settings/__next._head.txt +4 -4
- package/dist/web/settings/__next._index.txt +14 -14
- package/dist/web/settings/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/agents/__next._head.txt +4 -4
- package/dist/web/settings/agents/__next._index.txt +14 -14
- package/dist/web/settings/agents/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/mcps/__next._full.txt +26 -31
- package/dist/web/settings/mcps/__next._head.txt +4 -4
- package/dist/web/settings/mcps/__next._index.txt +14 -14
- package/dist/web/settings/mcps/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/models/__next._full.txt +26 -31
- package/dist/web/settings/models/__next._head.txt +4 -4
- package/dist/web/settings/models/__next._index.txt +14 -14
- package/dist/web/settings/models/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/output-styles/__next._full.txt +26 -31
- package/dist/web/settings/output-styles/__next._head.txt +4 -4
- package/dist/web/settings/output-styles/__next._index.txt +14 -14
- package/dist/web/settings/output-styles/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/prompts/__next._full.txt +26 -31
- package/dist/web/settings/prompts/__next._head.txt +4 -4
- package/dist/web/settings/prompts/__next._index.txt +14 -14
- package/dist/web/settings/prompts/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/providers/__next._full.txt +26 -31
- package/dist/web/settings/providers/__next._head.txt +4 -4
- package/dist/web/settings/providers/__next._index.txt +14 -14
- package/dist/web/settings/providers/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/skills/__next._full.txt +26 -31
- package/dist/web/settings/skills/__next._head.txt +4 -4
- package/dist/web/settings/skills/__next._index.txt +14 -14
- package/dist/web/settings/skills/__next._tree.txt +3 -8
- 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 +26 -31
- package/dist/web/settings/tools/__next._full.txt +38 -0
- package/dist/web/settings/tools/__next._head.txt +6 -0
- package/dist/web/settings/tools/__next._index.txt +15 -0
- package/dist/web/settings/tools/__next._tree.txt +3 -0
- package/dist/web/settings/tools/__next.settings.tools.__PAGE__.txt +9 -0
- package/dist/web/settings/tools/__next.settings.tools.txt +5 -0
- package/dist/web/settings/tools/__next.settings.txt +7 -0
- package/dist/web/settings/tools.html +1 -0
- package/dist/web/settings/tools.txt +38 -0
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +26 -31
- package/dist/web/workflows/__next._full.txt +34 -38
- package/dist/web/workflows/__next._head.txt +4 -4
- package/dist/web/workflows/__next._index.txt +14 -14
- package/dist/web/workflows/__next._tree.txt +3 -8
- 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 +34 -38
- package/dist/web/workspace/_/__next._full.txt +25 -29
- package/dist/web/workspace/_/__next._head.txt +4 -4
- package/dist/web/workspace/_/__next._index.txt +14 -14
- package/dist/web/workspace/_/__next._tree.txt +4 -8
- 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 -29
- package/dist/web/workspaces/__next._full.txt +24 -29
- package/dist/web/workspaces/__next._head.txt +4 -4
- package/dist/web/workspaces/__next._index.txt +14 -14
- package/dist/web/workspaces/__next._tree.txt +3 -8
- 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 -29
- package/dist/ws/agent-prompt.js +45 -8
- package/dist/ws/agent-runner.js +6 -4
- package/package.json +11 -10
- package/dist/web/_next/static/chunks/0-1bfvfwifh-m.js +0 -1
- package/dist/web/_next/static/chunks/04v-pqqs-2lvp.css +0 -1
- package/dist/web/_next/static/chunks/06w~.izyfylap.js +0 -1
- package/dist/web/_next/static/chunks/09t62a89~jesc.js +0 -3
- package/dist/web/_next/static/chunks/09y_3krccdd~u.js +0 -1
- package/dist/web/_next/static/chunks/0_e~hmntdfop9.js +0 -1
- package/dist/web/_next/static/chunks/0cke33d38fnby.js +0 -90
- package/dist/web/_next/static/chunks/0cyq~8xb~r5fc.js +0 -1
- package/dist/web/_next/static/chunks/0fxa1edqr7dve.js +0 -1
- package/dist/web/_next/static/chunks/0hra80eyuu37u.js +0 -1
- package/dist/web/_next/static/chunks/0ie7y4k2ncvnn.js +0 -1
- package/dist/web/_next/static/chunks/0igc~uli58ncw.js +0 -2
- package/dist/web/_next/static/chunks/0msb2mi3hiu5_.js +0 -67
- package/dist/web/_next/static/chunks/0p1n8bvfnpl41.js +0 -1
- package/dist/web/_next/static/chunks/0s_dva~eh2yhi.js +0 -3
- package/dist/web/_next/static/chunks/0typj55ox8d5i.js +0 -1
- package/dist/web/_next/static/chunks/0w2p4ldi2aymp.js +0 -1
- package/dist/web/_next/static/chunks/0zc0xgp5ourcn.js +0 -1
- package/dist/web/_next/static/chunks/0zmhdridea1s5.js +0 -90
- package/dist/web/_next/static/chunks/10.alq.6stmld.js +0 -1
- package/dist/web/_next/static/chunks/11b3zgk1etlkw.js +0 -7
- package/dist/web/_next/static/chunks/11qp8r5dotf7d.js +0 -1
- package/dist/web/_next/static/chunks/12mxlicp247c8.js +0 -1
- package/dist/web/_next/static/chunks/135w27dd8c19s.js +0 -5
- package/dist/web/_next/static/chunks/176dc-dtokxxi.js +0 -16
- package/dist/web/_next/static/chunks/17g-0pqre.anw.js +0 -1
- package/dist/web/_next/static/media/0a7740363b4d4863-s.1110aazvokzp..woff2 +0 -0
- package/dist/web/_next/static/media/0da9c7f357bd9d4d-s.0ek5sshv8wk3m.woff2 +0 -0
- package/dist/web/_next/static/media/1b99372b3eaef0c8-s.p.0gx2haw2tmll8.woff2 +0 -0
- package/dist/web/_next/static/media/41e95f694c5c4549-s.0r1jrq7neqdsq.woff2 +0 -0
- package/dist/web/_next/static/media/5c285b27cdda1fe8-s.p.0yo6-5yoeeudq.woff2 +0 -0
- package/dist/web/_next/static/media/5f9d24ebef5d5292-s.0esuu2f5si~v8.woff2 +0 -0
- package/dist/web/_next/static/media/6c55a692938ebbbc-s.0g6rbszwfgn9y.woff2 +0 -0
- package/dist/web/_next/static/media/8e6fa89aa22d24ec-s.p.0uvzar8hswo3p.woff2 +0 -0
- package/dist/web/_next/static/media/a218039a3287bcfd-s.p.17-1enzs_j91b.woff2 +0 -0
- package/dist/web/_next/static/media/b2ea385cb5ae8625-s.0kjod.kaq1k69.woff2 +0 -0
- package/dist/web/_next/static/media/bdc7e24a509eb931-s.0apt5mko2.qn3.woff2 +0 -0
- package/dist/web/_next/static/media/c3cb240f9c892514-s.163v2i5cux7-c.woff2 +0 -0
- package/dist/web/_next/static/media/e2334d715941921e-s.p.12skym0rqknxy.woff2 +0 -0
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → e8w3vd9Eov_LDYWj_0zsE}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → e8w3vd9Eov_LDYWj_0zsE}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{OoXAsPtrUWjC1l898FSvI → e8w3vd9Eov_LDYWj_0zsE}/_ssgManifest.js +0 -0
package/dist/adapters/git.js
CHANGED
|
@@ -36,26 +36,36 @@ function getGit(workspace) {
|
|
|
36
36
|
}
|
|
37
37
|
function mapStatus(raw) {
|
|
38
38
|
const files = [];
|
|
39
|
+
const addOrUpdate = (file) => {
|
|
40
|
+
const existing = files.find(x => x.path === file.path);
|
|
41
|
+
if (existing) {
|
|
42
|
+
Object.assign(existing, file, {
|
|
43
|
+
staged: existing.staged || file.staged,
|
|
44
|
+
conflicted: existing.conflicted || file.conflicted,
|
|
45
|
+
status: file.conflicted ? 'conflicted' : existing.status,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
files.push(file);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
39
52
|
for (const f of raw.staged) {
|
|
40
|
-
|
|
53
|
+
addOrUpdate({ path: f, status: mapStatusCode(raw.files.find(r => r.path === f)?.index), staged: true });
|
|
41
54
|
}
|
|
42
55
|
for (const f of raw.modified) {
|
|
43
|
-
|
|
44
|
-
files.push({ path: f, status: 'modified' });
|
|
45
|
-
}
|
|
56
|
+
addOrUpdate({ path: f, status: 'modified' });
|
|
46
57
|
}
|
|
47
58
|
for (const f of raw.not_added) {
|
|
48
|
-
|
|
59
|
+
addOrUpdate({ path: f, status: 'untracked' });
|
|
49
60
|
}
|
|
50
61
|
for (const f of raw.deleted) {
|
|
51
|
-
|
|
52
|
-
files.push({ path: f, status: 'deleted' });
|
|
53
|
-
}
|
|
62
|
+
addOrUpdate({ path: f, status: 'deleted' });
|
|
54
63
|
}
|
|
55
64
|
for (const f of raw.created) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
addOrUpdate({ path: f, status: 'added', staged: raw.staged.includes(f) });
|
|
66
|
+
}
|
|
67
|
+
for (const f of raw.conflicted) {
|
|
68
|
+
addOrUpdate({ path: f, status: 'conflicted', conflicted: true });
|
|
59
69
|
}
|
|
60
70
|
return {
|
|
61
71
|
branch: raw.current || 'HEAD',
|
|
@@ -67,6 +77,73 @@ function mapStatus(raw) {
|
|
|
67
77
|
deletions: 0,
|
|
68
78
|
};
|
|
69
79
|
}
|
|
80
|
+
async function getUpstreamRef(git, branch) {
|
|
81
|
+
const upstream = await git.raw(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'])
|
|
82
|
+
.then(v => v.trim())
|
|
83
|
+
.catch(() => '');
|
|
84
|
+
if (upstream)
|
|
85
|
+
return upstream;
|
|
86
|
+
if (!branch || branch === 'HEAD')
|
|
87
|
+
return null;
|
|
88
|
+
const originBranch = `origin/${branch}`;
|
|
89
|
+
const hasOriginBranch = await git.raw(['rev-parse', '--verify', '--quiet', originBranch])
|
|
90
|
+
.then(() => true)
|
|
91
|
+
.catch(() => false);
|
|
92
|
+
return hasOriginBranch ? originBranch : null;
|
|
93
|
+
}
|
|
94
|
+
function splitConflictSides(content) {
|
|
95
|
+
const left = [];
|
|
96
|
+
const right = [];
|
|
97
|
+
let mode = 'both';
|
|
98
|
+
let hasConflict = false;
|
|
99
|
+
for (const line of content.split('\n')) {
|
|
100
|
+
if (line.startsWith('<<<<<<< ')) {
|
|
101
|
+
hasConflict = true;
|
|
102
|
+
mode = 'left';
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (line.startsWith('=======')) {
|
|
106
|
+
mode = 'right';
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (line.startsWith('>>>>>>> ')) {
|
|
110
|
+
mode = 'both';
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (mode === 'both' || mode === 'left')
|
|
114
|
+
left.push(line);
|
|
115
|
+
if (mode === 'both' || mode === 'right')
|
|
116
|
+
right.push(line);
|
|
117
|
+
}
|
|
118
|
+
return { left: left.join('\n'), right: right.join('\n'), hasConflict };
|
|
119
|
+
}
|
|
120
|
+
async function buildWorkingDiff(git, rootDir, filePath, conflicted = false) {
|
|
121
|
+
const binary = isBinaryPath(filePath);
|
|
122
|
+
const workingContent = binary ? '' : await readFile(join(rootDir, filePath), 'utf-8').catch(() => '');
|
|
123
|
+
if (!binary && conflicted) {
|
|
124
|
+
const conflict = splitConflictSides(workingContent);
|
|
125
|
+
if (conflict.hasConflict) {
|
|
126
|
+
return {
|
|
127
|
+
path: filePath,
|
|
128
|
+
oldContent: conflict.left,
|
|
129
|
+
newContent: conflict.right,
|
|
130
|
+
isBinary: false,
|
|
131
|
+
isNew: false,
|
|
132
|
+
isDeleted: false,
|
|
133
|
+
isConflict: true,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const oldContent = binary ? '' : await git.show([`HEAD:${filePath}`]).catch(() => '');
|
|
138
|
+
return {
|
|
139
|
+
path: filePath,
|
|
140
|
+
oldContent,
|
|
141
|
+
newContent: workingContent,
|
|
142
|
+
isBinary: binary,
|
|
143
|
+
isNew: !oldContent,
|
|
144
|
+
isDeleted: !workingContent,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
70
147
|
function mapStatusCode(code) {
|
|
71
148
|
switch (code) {
|
|
72
149
|
case 'A': return 'added';
|
|
@@ -83,6 +160,19 @@ export async function gitStatus(workspaceId) {
|
|
|
83
160
|
const git = getGit(ws);
|
|
84
161
|
const raw = await git.status();
|
|
85
162
|
const result = mapStatus(raw);
|
|
163
|
+
try {
|
|
164
|
+
const headHash = await git.revparse(['--short', 'HEAD']);
|
|
165
|
+
result.headHash = headHash.trim();
|
|
166
|
+
}
|
|
167
|
+
catch { }
|
|
168
|
+
try {
|
|
169
|
+
const upstream = await getUpstreamRef(git, result.branch);
|
|
170
|
+
if (upstream) {
|
|
171
|
+
const remoteHeadHash = await git.revparse(['--short', upstream]);
|
|
172
|
+
result.remoteHeadHash = remoteHeadHash.trim();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch { }
|
|
86
176
|
if (!result.clean) {
|
|
87
177
|
try {
|
|
88
178
|
// Tracked changes: modified/deleted/renamed
|
|
@@ -122,66 +212,73 @@ export async function gitDiff(workspaceId, filePath) {
|
|
|
122
212
|
throw new Error('Workspace not found');
|
|
123
213
|
const git = getGit(ws);
|
|
124
214
|
const diffs = [];
|
|
215
|
+
const status = await git.status();
|
|
216
|
+
const conflicted = new Set(status.conflicted);
|
|
125
217
|
if (filePath) {
|
|
126
|
-
|
|
127
|
-
const oldContent = await git.show([`HEAD:${filePath}`]).catch(() => '');
|
|
128
|
-
const newContent = await import('node:fs/promises').then(fs => fs.readFile(`${ws.boundDirs[0]}/${filePath}`, 'utf-8')).catch(() => '');
|
|
129
|
-
diffs.push({
|
|
130
|
-
path: filePath,
|
|
131
|
-
oldContent: isBinaryPath(filePath) ? '' : oldContent,
|
|
132
|
-
newContent: isBinaryPath(filePath) ? '' : newContent,
|
|
133
|
-
isBinary: isBinaryPath(filePath),
|
|
134
|
-
isNew: !oldContent,
|
|
135
|
-
isDeleted: !newContent,
|
|
136
|
-
});
|
|
218
|
+
diffs.push(await buildWorkingDiff(git, ws.boundDirs[0], filePath, conflicted.has(filePath)));
|
|
137
219
|
}
|
|
138
220
|
else {
|
|
139
221
|
const raw = await git.diff(['--name-only']);
|
|
140
|
-
const
|
|
222
|
+
const cachedRaw = await git.diff(['--cached', '--name-only']);
|
|
223
|
+
const files = Array.from(new Set([
|
|
224
|
+
...raw.split('\n').filter(Boolean),
|
|
225
|
+
...cachedRaw.split('\n').filter(Boolean),
|
|
226
|
+
...status.not_added,
|
|
227
|
+
...status.conflicted,
|
|
228
|
+
]));
|
|
141
229
|
for (const f of files) {
|
|
142
|
-
|
|
143
|
-
const oldContent = binary ? '' : await git.show([`HEAD:${f}`]).catch(() => '');
|
|
144
|
-
const newContent = binary ? '' : await import('node:fs/promises').then(fs => fs.readFile(`${ws.boundDirs[0]}/${f}`, 'utf-8')).catch(() => '');
|
|
145
|
-
diffs.push({
|
|
146
|
-
path: f,
|
|
147
|
-
oldContent,
|
|
148
|
-
newContent,
|
|
149
|
-
isBinary: binary,
|
|
150
|
-
isNew: !oldContent,
|
|
151
|
-
isDeleted: !newContent,
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
// Also check untracked (staged new files)
|
|
155
|
-
const status = await git.status();
|
|
156
|
-
for (const f of status.not_added) {
|
|
157
|
-
const binary = isBinaryPath(f);
|
|
158
|
-
const newContent = binary ? '' : await import('node:fs/promises').then(fs => fs.readFile(`${ws.boundDirs[0]}/${f}`, 'utf-8')).catch(() => '');
|
|
159
|
-
if (newContent || binary) {
|
|
160
|
-
diffs.push({
|
|
161
|
-
path: f,
|
|
162
|
-
oldContent: '',
|
|
163
|
-
newContent: binary ? '' : newContent,
|
|
164
|
-
isBinary: binary,
|
|
165
|
-
isNew: true,
|
|
166
|
-
isDeleted: false,
|
|
167
|
-
});
|
|
168
|
-
}
|
|
230
|
+
diffs.push(await buildWorkingDiff(git, ws.boundDirs[0], f, conflicted.has(f)));
|
|
169
231
|
}
|
|
170
232
|
}
|
|
171
233
|
return diffs;
|
|
172
234
|
}
|
|
235
|
+
export async function gitStage(workspaceId, filePath) {
|
|
236
|
+
const ws = getWorkspace(workspaceId);
|
|
237
|
+
if (!ws)
|
|
238
|
+
throw new Error('Workspace not found');
|
|
239
|
+
const git = getGit(ws);
|
|
240
|
+
await git.add(filePath);
|
|
241
|
+
}
|
|
242
|
+
export async function gitUnstage(workspaceId, filePath) {
|
|
243
|
+
const ws = getWorkspace(workspaceId);
|
|
244
|
+
if (!ws)
|
|
245
|
+
throw new Error('Workspace not found');
|
|
246
|
+
const git = getGit(ws);
|
|
247
|
+
await git.raw(['restore', '--staged', '--', filePath]).catch(async () => {
|
|
248
|
+
await git.raw(['reset', 'HEAD', '--', filePath]);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
export async function gitResolveFile(workspaceId, filePath, content, stage = true) {
|
|
252
|
+
const ws = getWorkspace(workspaceId);
|
|
253
|
+
if (!ws)
|
|
254
|
+
throw new Error('Workspace not found');
|
|
255
|
+
const git = getGit(ws);
|
|
256
|
+
await writeFile(join(ws.boundDirs[0], filePath), content, 'utf-8');
|
|
257
|
+
if (stage)
|
|
258
|
+
await git.add(filePath);
|
|
259
|
+
}
|
|
173
260
|
export async function gitLog(workspaceId, maxCount = 50) {
|
|
174
261
|
const ws = getWorkspace(workspaceId);
|
|
175
262
|
if (!ws)
|
|
176
263
|
throw new Error('Workspace not found');
|
|
177
264
|
const git = getGit(ws);
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
265
|
+
const status = await git.status();
|
|
266
|
+
const upstream = await getUpstreamRef(git, status.current || 'HEAD');
|
|
267
|
+
const refs = upstream ? ['HEAD', upstream] : ['HEAD'];
|
|
268
|
+
const pretty = '%H%x1f%s%x1f%an%x1f%aI%x1e';
|
|
269
|
+
const raw = await git.raw(['log', `--max-count=${maxCount}`, `--pretty=format:${pretty}`, ...refs]);
|
|
270
|
+
return raw.split('\x1e')
|
|
271
|
+
.map(record => record.trim())
|
|
272
|
+
.filter(Boolean)
|
|
273
|
+
.map(record => {
|
|
274
|
+
const [hash = '', message = '', author = '', date = ''] = record.split('\x1f');
|
|
275
|
+
return {
|
|
276
|
+
hash: hash.substring(0, 7),
|
|
277
|
+
message,
|
|
278
|
+
author,
|
|
279
|
+
date,
|
|
280
|
+
};
|
|
281
|
+
});
|
|
185
282
|
}
|
|
186
283
|
export async function gitCommit(workspaceId, message) {
|
|
187
284
|
const ws = getWorkspace(workspaceId);
|
|
@@ -274,6 +371,13 @@ export async function gitPush(workspaceId) {
|
|
|
274
371
|
throw new Error('No remote repository configured. Please add a remote first.');
|
|
275
372
|
await git.push('origin', branch);
|
|
276
373
|
}
|
|
374
|
+
export async function gitFetch(workspaceId) {
|
|
375
|
+
const ws = getWorkspace(workspaceId);
|
|
376
|
+
if (!ws)
|
|
377
|
+
throw new Error('Workspace not found');
|
|
378
|
+
const git = getGit(ws);
|
|
379
|
+
await git.fetch('origin');
|
|
380
|
+
}
|
|
277
381
|
export async function gitPull(workspaceId) {
|
|
278
382
|
const ws = getWorkspace(workspaceId);
|
|
279
383
|
if (!ws)
|
|
@@ -28,13 +28,36 @@ export async function generateAgentDesign(userPrompt) {
|
|
|
28
28
|
apiBase: maskUrl(config.apiBase),
|
|
29
29
|
promptLength: prompt.length,
|
|
30
30
|
});
|
|
31
|
-
const content = await
|
|
31
|
+
const content = await requestText(config, buildDesignSystemPrompt(config), prompt);
|
|
32
32
|
console.info('[agent-designer] model text extracted', {
|
|
33
33
|
length: content.length,
|
|
34
34
|
preview: content.slice(0, 500),
|
|
35
35
|
});
|
|
36
36
|
return normalizeDesign(parseJsonObject(content));
|
|
37
37
|
}
|
|
38
|
+
export async function optimizeAgentPrompt(userPrompt, currentPrompt) {
|
|
39
|
+
const prompt = userPrompt.trim();
|
|
40
|
+
if (!prompt)
|
|
41
|
+
throw new Error('prompt is required');
|
|
42
|
+
const config = resolveModelConfig();
|
|
43
|
+
if (!config) {
|
|
44
|
+
throw new Error(`Configure model settings for ${AGENT_GENERATOR_PRESET_ID} before optimizing prompts.`);
|
|
45
|
+
}
|
|
46
|
+
console.info('[agent-designer] optimizing agent prompt', {
|
|
47
|
+
agentId: AGENT_GENERATOR_PRESET_ID,
|
|
48
|
+
provider: config.modelProvider ?? inferProvider(config.apiBase),
|
|
49
|
+
modelId: config.modelId,
|
|
50
|
+
apiBase: maskUrl(config.apiBase),
|
|
51
|
+
promptLength: prompt.length,
|
|
52
|
+
currentPromptLength: currentPrompt.trim().length,
|
|
53
|
+
});
|
|
54
|
+
const content = await requestText(config, buildOptimizationSystemPrompt(config), buildPromptOptimizationUserPrompt(prompt, currentPrompt));
|
|
55
|
+
console.info('[agent-designer] optimized prompt received', {
|
|
56
|
+
length: content.length,
|
|
57
|
+
preview: content.slice(0, 500),
|
|
58
|
+
});
|
|
59
|
+
return { systemPrompt: normalizePrompt(content) };
|
|
60
|
+
}
|
|
38
61
|
function resolveModelConfig() {
|
|
39
62
|
const preset = readAgentTemplate(AGENT_GENERATOR_PRESET_ID);
|
|
40
63
|
if (preset?.apiBase && preset.apiKey && preset.modelId) {
|
|
@@ -51,14 +74,17 @@ function resolveModelConfig() {
|
|
|
51
74
|
return null;
|
|
52
75
|
}
|
|
53
76
|
async function requestDesign(config, userPrompt) {
|
|
77
|
+
return requestText(config, buildDesignSystemPrompt(config), userPrompt);
|
|
78
|
+
}
|
|
79
|
+
async function requestText(config, systemPrompt, userPrompt) {
|
|
54
80
|
const provider = config.modelProvider ?? inferProvider(config.apiBase);
|
|
55
81
|
if (provider === 'anthropic-messages')
|
|
56
|
-
return requestAnthropic(config, userPrompt);
|
|
82
|
+
return requestAnthropic(config, systemPrompt, userPrompt);
|
|
57
83
|
if (provider === 'gemini-generate-content')
|
|
58
|
-
return requestGemini(config, userPrompt);
|
|
59
|
-
return requestOpenAICompatible(config, userPrompt, provider === 'openai-responses' || provider === 'openai-responses-to-anthropic-messages');
|
|
84
|
+
return requestGemini(config, systemPrompt, userPrompt);
|
|
85
|
+
return requestOpenAICompatible(config, systemPrompt, userPrompt, provider === 'openai-responses' || provider === 'openai-responses-to-anthropic-messages');
|
|
60
86
|
}
|
|
61
|
-
async function requestOpenAICompatible(config, userPrompt, useResponsesApi) {
|
|
87
|
+
async function requestOpenAICompatible(config, systemPrompt, userPrompt, useResponsesApi) {
|
|
62
88
|
const url = joinUrl(config.apiBase, useResponsesApi ? '/responses' : '/chat/completions');
|
|
63
89
|
const response = await fetch(url, {
|
|
64
90
|
method: 'POST',
|
|
@@ -69,14 +95,14 @@ async function requestOpenAICompatible(config, userPrompt, useResponsesApi) {
|
|
|
69
95
|
body: JSON.stringify(useResponsesApi
|
|
70
96
|
? {
|
|
71
97
|
model: config.modelId,
|
|
72
|
-
input: `${
|
|
98
|
+
input: `${systemPrompt}\n\nUser request:\n${userPrompt}`,
|
|
73
99
|
temperature: config.temperature ?? 0.2,
|
|
74
100
|
max_output_tokens: config.maxTokens,
|
|
75
101
|
}
|
|
76
102
|
: {
|
|
77
103
|
model: config.modelId,
|
|
78
104
|
messages: [
|
|
79
|
-
{ role: 'system', content:
|
|
105
|
+
{ role: 'system', content: systemPrompt },
|
|
80
106
|
{ role: 'user', content: userPrompt },
|
|
81
107
|
],
|
|
82
108
|
temperature: config.temperature ?? 0.2,
|
|
@@ -88,7 +114,7 @@ async function requestOpenAICompatible(config, userPrompt, useResponsesApi) {
|
|
|
88
114
|
throw new Error(body.error || `Agent design generation failed with status ${response.status}`);
|
|
89
115
|
return body.text;
|
|
90
116
|
}
|
|
91
|
-
async function requestAnthropic(config, userPrompt) {
|
|
117
|
+
async function requestAnthropic(config, systemPrompt, userPrompt) {
|
|
92
118
|
const response = await fetch(getAnthropicMessagesUrl(config.apiBase), {
|
|
93
119
|
method: 'POST',
|
|
94
120
|
headers: {
|
|
@@ -98,7 +124,7 @@ async function requestAnthropic(config, userPrompt) {
|
|
|
98
124
|
},
|
|
99
125
|
body: JSON.stringify({
|
|
100
126
|
model: config.modelId,
|
|
101
|
-
system:
|
|
127
|
+
system: systemPrompt,
|
|
102
128
|
messages: [{ role: 'user', content: userPrompt }],
|
|
103
129
|
max_tokens: config.maxTokens ?? 4096,
|
|
104
130
|
temperature: config.temperature ?? 0.2,
|
|
@@ -109,7 +135,7 @@ async function requestAnthropic(config, userPrompt) {
|
|
|
109
135
|
throw new Error(body.error || `Agent design generation failed with status ${response.status}`);
|
|
110
136
|
return body.text;
|
|
111
137
|
}
|
|
112
|
-
async function requestGemini(config, userPrompt) {
|
|
138
|
+
async function requestGemini(config, systemPrompt, userPrompt) {
|
|
113
139
|
const response = await fetch(joinUrl(config.apiBase, `/models/${encodeURIComponent(config.modelId)}:generateContent`), {
|
|
114
140
|
method: 'POST',
|
|
115
141
|
headers: {
|
|
@@ -117,7 +143,7 @@ async function requestGemini(config, userPrompt) {
|
|
|
117
143
|
'Content-Type': 'application/json',
|
|
118
144
|
},
|
|
119
145
|
body: JSON.stringify({
|
|
120
|
-
systemInstruction: { parts: [{ text:
|
|
146
|
+
systemInstruction: { parts: [{ text: systemPrompt }] },
|
|
121
147
|
contents: [{ role: 'user', parts: [{ text: userPrompt }] }],
|
|
122
148
|
generationConfig: {
|
|
123
149
|
temperature: config.temperature ?? 0.2,
|
|
@@ -130,12 +156,40 @@ async function requestGemini(config, userPrompt) {
|
|
|
130
156
|
throw new Error(body.error || `Agent design generation failed with status ${response.status}`);
|
|
131
157
|
return body.text;
|
|
132
158
|
}
|
|
133
|
-
function
|
|
159
|
+
function buildDesignSystemPrompt(config) {
|
|
134
160
|
const custom = config.systemPrompt?.trim();
|
|
135
161
|
if (!custom)
|
|
136
162
|
return SYSTEM_PROMPT;
|
|
137
163
|
return `${custom}\n\n${SYSTEM_PROMPT}`;
|
|
138
164
|
}
|
|
165
|
+
function buildOptimizationSystemPrompt(config) {
|
|
166
|
+
const custom = config.systemPrompt?.trim();
|
|
167
|
+
const base = [
|
|
168
|
+
'You optimize agent system prompts.',
|
|
169
|
+
'Return only the rewritten prompt text.',
|
|
170
|
+
'Do not wrap the result in markdown fences.',
|
|
171
|
+
'Do not add commentary, bullets about the process, or any explanation outside the prompt.',
|
|
172
|
+
'Keep the prompt actionable, concise, and directly usable as a system prompt.',
|
|
173
|
+
'Preserve important constraints from the current prompt unless the user request clearly asks to change them.',
|
|
174
|
+
].join('\n');
|
|
175
|
+
if (!custom)
|
|
176
|
+
return base;
|
|
177
|
+
return `${custom}\n\n${base}`;
|
|
178
|
+
}
|
|
179
|
+
function buildPromptOptimizationUserPrompt(userRequest, currentPrompt) {
|
|
180
|
+
return [
|
|
181
|
+
'User request:',
|
|
182
|
+
userRequest,
|
|
183
|
+
'',
|
|
184
|
+
'Current system prompt:',
|
|
185
|
+
currentPrompt.trim() || '(empty)',
|
|
186
|
+
'',
|
|
187
|
+
'Rewrite the current system prompt according to the user request. Return only the final prompt text.',
|
|
188
|
+
].join('\n');
|
|
189
|
+
}
|
|
190
|
+
function normalizePrompt(text) {
|
|
191
|
+
return text.trim().replace(/^```(?:markdown|md)?\s*/i, '').replace(/\s*```$/i, '');
|
|
192
|
+
}
|
|
139
193
|
async function readResponseBody(response) {
|
|
140
194
|
const raw = await response.text();
|
|
141
195
|
if (!raw)
|
|
@@ -5,7 +5,7 @@ import * as issueService from '../services/issue.js';
|
|
|
5
5
|
import * as taskService from '../services/task.js';
|
|
6
6
|
import * as workspaceService from '../services/workspace.js';
|
|
7
7
|
import { mapWorkflowToTaskDrafts, validateWorkflowForRun } from '../services/workflow.js';
|
|
8
|
-
import { createIssueFunctionTools } from '../services/builtin-tools.js';
|
|
8
|
+
import { createIssueFunctionTools } from '../services/builtin-tools/index.js';
|
|
9
9
|
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
10
10
|
import { prependPersistentAgentContext } from '../services/persistent-agent-context.js';
|
|
11
11
|
import { completeIssueAgentProgress, createIssueAgentProgress, createIssueAgentProgressTracker } from './issue-agent-progress.js';
|
package/dist/app.js
CHANGED
|
@@ -7,7 +7,7 @@ import { createServer } from 'node:http';
|
|
|
7
7
|
import { WebSocketServer } from 'ws';
|
|
8
8
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
9
9
|
import { writeFile } from 'node:fs/promises';
|
|
10
|
-
import { join, dirname, basename } from 'node:path';
|
|
10
|
+
import { join, dirname, extname, basename } from 'node:path';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
import workspaceRouter from './routes/workspace.js';
|
|
13
13
|
import fileRouter from './routes/file.js';
|
|
@@ -31,7 +31,10 @@ import subscriptionRouter from './routes/subscription.js';
|
|
|
31
31
|
import agentSseRouter from './routes/agent-sse.js';
|
|
32
32
|
import searchRouter from './routes/search.js';
|
|
33
33
|
import notificationRouter from './routes/notification.js';
|
|
34
|
+
import databaseRouter from './routes/database.js';
|
|
35
|
+
import kanbanRouter from './routes/kanban.js';
|
|
34
36
|
import speechRecognitionRouter, { handleSpeechStream } from './routes/speech-recognition.js';
|
|
37
|
+
import agentCommandsRouter from './routes/agent-commands.js';
|
|
35
38
|
import { getUserSettings, setUserAvatarUrl, removeUserAvatarUrl } from './storage/user-settings-store.js';
|
|
36
39
|
import { authMiddleware, verifyToken } from './middleware/auth.js';
|
|
37
40
|
import { handleConnection } from './ws/handler.js';
|
|
@@ -158,6 +161,49 @@ app.post('/api/upload/avatar', async (req, res) => {
|
|
|
158
161
|
await writeFile(join(avatarsDir, name), Buffer.from(base64, 'base64'));
|
|
159
162
|
res.json({ url: `/static/avatars/${name}` });
|
|
160
163
|
});
|
|
164
|
+
// Font upload
|
|
165
|
+
const FONT_EXTS = new Set(['.ttf', '.otf', '.woff', '.woff2']);
|
|
166
|
+
const fontsDir = join(publicDir, 'fonts');
|
|
167
|
+
if (!existsSync(fontsDir))
|
|
168
|
+
mkdirSync(fontsDir, { recursive: true });
|
|
169
|
+
app.get('/api/fonts', (_req, res) => {
|
|
170
|
+
if (!existsSync(fontsDir)) {
|
|
171
|
+
res.json([]);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const fonts = readdirSync(fontsDir).filter(f => FONT_EXTS.has(extname(f).toLowerCase()));
|
|
175
|
+
res.json(fonts.map(f => ({ name: f, url: `/static/fonts/${f}` })));
|
|
176
|
+
});
|
|
177
|
+
app.post('/api/fonts/upload', async (req, res) => {
|
|
178
|
+
const { name, content } = req.body;
|
|
179
|
+
if (!name || !content) {
|
|
180
|
+
res.status(400).json({ error: 'name and content are required' });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const ext = extname(name).toLowerCase();
|
|
184
|
+
if (!FONT_EXTS.has(ext)) {
|
|
185
|
+
res.status(400).json({ error: 'Unsupported font format' });
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const safeName = basename(name).replace(/[^a-zA-Z0-9._-]/g, '_');
|
|
189
|
+
await writeFile(join(fontsDir, safeName), Buffer.from(content, 'base64'));
|
|
190
|
+
res.json({ name: safeName, url: `/static/fonts/${safeName}` });
|
|
191
|
+
});
|
|
192
|
+
app.delete('/api/fonts/:name', (req, res) => {
|
|
193
|
+
const name = basename(req.params.name);
|
|
194
|
+
const ext = extname(name).toLowerCase();
|
|
195
|
+
if (!FONT_EXTS.has(ext)) {
|
|
196
|
+
res.status(400).json({ error: 'Invalid font file' });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const filePath = join(fontsDir, name);
|
|
200
|
+
if (!existsSync(filePath)) {
|
|
201
|
+
res.status(404).json({ error: 'Font not found' });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
import('node:fs').then(fs => fs.unlinkSync(filePath));
|
|
205
|
+
res.json({ ok: true });
|
|
206
|
+
});
|
|
161
207
|
// User settings
|
|
162
208
|
app.get('/api/user/settings', (_req, res) => {
|
|
163
209
|
const settings = getUserSettings();
|
|
@@ -206,6 +252,8 @@ app.post('/api/git-config', async (req, res) => {
|
|
|
206
252
|
}
|
|
207
253
|
});
|
|
208
254
|
app.use('/api/workspaces/:id/search', searchRouter);
|
|
255
|
+
app.use('/api/workspaces/:id/database', databaseRouter);
|
|
256
|
+
app.use('/api/workspaces/:id/kanban', kanbanRouter);
|
|
209
257
|
app.use('/api/workspaces/:id/notifications', notificationRouter);
|
|
210
258
|
app.use('/api/agents', agentRouter);
|
|
211
259
|
app.use('/api', llmRouter);
|
|
@@ -216,6 +264,7 @@ app.use('/api/output-styles', outputStyleRouter);
|
|
|
216
264
|
app.use('/api/mcps', mcpRouter);
|
|
217
265
|
app.use('/api/subscriptions', subscriptionRouter);
|
|
218
266
|
app.use('/api/speech-recognition', speechRecognitionRouter);
|
|
267
|
+
app.use('/api/agent-commands', agentCommandsRouter);
|
|
219
268
|
// Serve static web frontend in production (after API routes, before catch-all)
|
|
220
269
|
const webDir = resolveRuntimeDir('web');
|
|
221
270
|
if (existsSync(webDir)) {
|
package/dist/package.json
CHANGED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { listAgentsWithCommands, listAllCommands, listCommands, getCommand, createCommand, updateCommand, deleteCommand, applyCommandToAgents, } from '../services/agent-commands.js';
|
|
3
|
+
const router = Router();
|
|
4
|
+
router.get('/agents', (_req, res) => {
|
|
5
|
+
res.json(listAgentsWithCommands());
|
|
6
|
+
});
|
|
7
|
+
router.get('/all', (_req, res) => {
|
|
8
|
+
res.json(listAllCommands());
|
|
9
|
+
});
|
|
10
|
+
router.get('/:agentId', (req, res) => {
|
|
11
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
12
|
+
res.json(listCommands(agentId));
|
|
13
|
+
});
|
|
14
|
+
router.get('/:agentId/:name', (req, res) => {
|
|
15
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
16
|
+
const name = typeof req.params.name === 'string' ? req.params.name : req.params.name[0];
|
|
17
|
+
const group = req.query.group;
|
|
18
|
+
const cmd = getCommand(agentId, name, group);
|
|
19
|
+
if (!cmd) {
|
|
20
|
+
res.status(404).json({ error: 'Command not found' });
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
res.json(cmd);
|
|
24
|
+
});
|
|
25
|
+
router.post('/:agentId', (req, res) => {
|
|
26
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
27
|
+
const { name, content, group } = req.body;
|
|
28
|
+
if (!name || !content) {
|
|
29
|
+
res.status(400).json({ error: 'name and content required' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
res.json(createCommand(agentId, name, content, group));
|
|
33
|
+
});
|
|
34
|
+
router.put('/:agentId/:name', (req, res) => {
|
|
35
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
36
|
+
const name = typeof req.params.name === 'string' ? req.params.name : req.params.name[0];
|
|
37
|
+
const { content, group } = req.body;
|
|
38
|
+
if (!content) {
|
|
39
|
+
res.status(400).json({ error: 'content required' });
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const cmd = updateCommand(agentId, name, content, group);
|
|
43
|
+
if (!cmd) {
|
|
44
|
+
res.status(404).json({ error: 'Command not found' });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
res.json(cmd);
|
|
48
|
+
});
|
|
49
|
+
router.delete('/:agentId/:name', (req, res) => {
|
|
50
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
51
|
+
const name = typeof req.params.name === 'string' ? req.params.name : req.params.name[0];
|
|
52
|
+
const group = req.query.group;
|
|
53
|
+
const ok = deleteCommand(agentId, name, group);
|
|
54
|
+
if (!ok) {
|
|
55
|
+
res.status(404).json({ error: 'Command not found' });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
res.json({ success: true });
|
|
59
|
+
});
|
|
60
|
+
router.post('/:agentId/:name/apply', (req, res) => {
|
|
61
|
+
const agentId = typeof req.params.agentId === 'string' ? req.params.agentId : req.params.agentId[0];
|
|
62
|
+
const name = typeof req.params.name === 'string' ? req.params.name : req.params.name[0];
|
|
63
|
+
const { group, agentIds } = req.body;
|
|
64
|
+
if (!Array.isArray(agentIds) || agentIds.length === 0) {
|
|
65
|
+
res.status(400).json({ error: 'agentIds required' });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const applied = applyCommandToAgents(agentId, name, group || '', agentIds);
|
|
69
|
+
res.json({ applied });
|
|
70
|
+
});
|
|
71
|
+
export default router;
|
|
72
|
+
//# sourceMappingURL=agent-commands.js.map
|
package/dist/routes/agent-sse.js
CHANGED
|
@@ -143,11 +143,17 @@ function prepareSse(res) {
|
|
|
143
143
|
res.setHeader('Content-Type', 'text/event-stream; charset=utf-8');
|
|
144
144
|
res.setHeader('Cache-Control', 'no-cache, no-transform');
|
|
145
145
|
res.setHeader('Connection', 'keep-alive');
|
|
146
|
+
res.setHeader('X-Accel-Buffering', 'no');
|
|
146
147
|
res.flushHeaders?.();
|
|
148
|
+
res.socket?.setNoDelay?.(true);
|
|
147
149
|
}
|
|
148
150
|
function writeSse(res, event, data) {
|
|
149
151
|
res.write(`event: ${event}\n`);
|
|
150
152
|
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
153
|
+
// Force flush — compression middleware and some proxies buffer small writes
|
|
154
|
+
const flushable = res;
|
|
155
|
+
if (typeof flushable.flush === 'function')
|
|
156
|
+
flushable.flush();
|
|
151
157
|
}
|
|
152
158
|
function resolveUserPrompt(body) {
|
|
153
159
|
const direct = body.prompt ?? body.message;
|
package/dist/routes/agent.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import * as agentService from '../services/agent.js';
|
|
3
|
-
import { generateAgentDesign } from '../agents/agent-designer.js';
|
|
3
|
+
import { generateAgentDesign, optimizeAgentPrompt } from '../agents/agent-designer.js';
|
|
4
4
|
const router = Router({ mergeParams: true });
|
|
5
5
|
router.get('/usage/dashboard', (req, res) => {
|
|
6
6
|
const days = Number(req.query.days ?? 30);
|
|
@@ -36,6 +36,20 @@ router.post('/presets/generate', async (req, res) => {
|
|
|
36
36
|
res.status(400).json({ error: err instanceof Error ? err.message : 'agent generation failed' });
|
|
37
37
|
}
|
|
38
38
|
});
|
|
39
|
+
router.post('/presets/optimize-prompt', async (req, res) => {
|
|
40
|
+
const { prompt, currentPrompt } = req.body;
|
|
41
|
+
if (!prompt?.trim()) {
|
|
42
|
+
res.status(400).json({ error: 'prompt is required' });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
res.json(await optimizeAgentPrompt(prompt, currentPrompt ?? ''));
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error('[agent-designer] optimize failed', err);
|
|
50
|
+
res.status(400).json({ error: err instanceof Error ? err.message : 'prompt optimization failed' });
|
|
51
|
+
}
|
|
52
|
+
});
|
|
39
53
|
router.post('/presets/test-connection', async (req, res) => {
|
|
40
54
|
const workspaceId = req.params.id;
|
|
41
55
|
const data = req.body;
|