@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
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import * as store from '../storage/database-store.js';
|
|
5
|
+
import * as databaseVector from '../services/database-vector.js';
|
|
6
|
+
import * as agentService from '../services/agent.js';
|
|
7
|
+
import * as workspaceService from '../services/workspace.js';
|
|
8
|
+
import { createDatabaseFunctionTools } from '../services/builtin-tools/index.js';
|
|
9
|
+
import { createAgentRuntime } from '../adapters/agent-runtime.js';
|
|
10
|
+
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
11
|
+
import { getDataDir, ensureDir } from '../storage/json-store.js';
|
|
12
|
+
import { generateAgentDesign } from '../agents/agent-designer.js';
|
|
13
|
+
const router = Router({ mergeParams: true });
|
|
14
|
+
const pendingContentSaves = new Map();
|
|
15
|
+
const CONTENT_SAVE_IDLE_MS = 30_000;
|
|
16
|
+
const DATABASE_AGENT_ID = 'database-agent';
|
|
17
|
+
const DATABASE_AGENT_TOOLS = [
|
|
18
|
+
'ListDatabases',
|
|
19
|
+
'ListDatabaseNodes',
|
|
20
|
+
'SearchDatabaseNodes',
|
|
21
|
+
'QueryDatabaseVectors',
|
|
22
|
+
'ReadDatabaseNode',
|
|
23
|
+
'ListDatabaseNodeVersions',
|
|
24
|
+
'CreateDatabaseNode',
|
|
25
|
+
'WriteDatabaseNode',
|
|
26
|
+
'DeleteDatabaseNode',
|
|
27
|
+
'MoveDatabaseNode',
|
|
28
|
+
'UpdateDatabaseNodeMeta',
|
|
29
|
+
];
|
|
30
|
+
const wid = (req) => req.params.id;
|
|
31
|
+
const databaseId = (req) => req.query.databaseId || store.getDefaultDatabase(wid(req)).id;
|
|
32
|
+
router.get('/agent-presets', (req, res) => {
|
|
33
|
+
res.json([readDatabaseAgent(wid(req))]);
|
|
34
|
+
});
|
|
35
|
+
router.get('/agent-presets/:presetId', (req, res) => {
|
|
36
|
+
if (req.params.presetId !== DATABASE_AGENT_ID)
|
|
37
|
+
return res.status(404).json({ error: 'database agent not found' });
|
|
38
|
+
res.json(readDatabaseAgent(wid(req)));
|
|
39
|
+
});
|
|
40
|
+
router.put('/agent-presets/:presetId', (req, res) => {
|
|
41
|
+
if (req.params.presetId !== DATABASE_AGENT_ID)
|
|
42
|
+
return res.status(404).json({ error: 'database agent not found' });
|
|
43
|
+
res.json(writeDatabaseAgent(wid(req), req.body));
|
|
44
|
+
});
|
|
45
|
+
router.post('/agent-presets/test-connection', async (req, res) => {
|
|
46
|
+
const result = await agentService.testConnection(wid(req), req.body);
|
|
47
|
+
if (!result)
|
|
48
|
+
return res.status(404).json({ error: 'workspace not found' });
|
|
49
|
+
res.status(result.success ? 200 : 400).json(result);
|
|
50
|
+
});
|
|
51
|
+
router.post('/agent-presets/generate', async (req, res) => {
|
|
52
|
+
const { prompt } = req.body;
|
|
53
|
+
if (!prompt?.trim())
|
|
54
|
+
return res.status(400).json({ error: 'prompt is required' });
|
|
55
|
+
try {
|
|
56
|
+
res.json(await generateAgentDesign(prompt));
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
res.status(400).json({ error: err instanceof Error ? err.message : 'agent generation failed' });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
router.post('/chat', async (req, res) => {
|
|
63
|
+
const workspaceId = wid(req);
|
|
64
|
+
const { message, history } = req.body;
|
|
65
|
+
const prompt = message?.trim();
|
|
66
|
+
if (!prompt)
|
|
67
|
+
return res.status(400).json({ error: 'message is required' });
|
|
68
|
+
const workspace = workspaceService.getById(workspaceId);
|
|
69
|
+
if (!workspace)
|
|
70
|
+
return res.status(404).json({ error: 'workspace not found' });
|
|
71
|
+
const agent = readDatabaseAgent(workspaceId);
|
|
72
|
+
if (agent.enabled === false)
|
|
73
|
+
return res.status(400).json({ error: 'database agent is disabled' });
|
|
74
|
+
const workingDir = workspace.boundDirs[0] || process.cwd();
|
|
75
|
+
const functionTools = createDatabaseFunctionTools(workspaceId, agent.tools);
|
|
76
|
+
const runtime = createAgentRuntime({
|
|
77
|
+
kind: agent.runtimeKind,
|
|
78
|
+
provider: agent.modelProvider,
|
|
79
|
+
model: agent.modelId,
|
|
80
|
+
apiKey: agent.apiKey,
|
|
81
|
+
baseURL: getRuntimeBaseURL(agent.modelProvider, agent.apiBase),
|
|
82
|
+
adapterBaseURL: agent.apiBase,
|
|
83
|
+
...getThinkingRuntimeConfig(agent),
|
|
84
|
+
});
|
|
85
|
+
const result = await runtime.execute(buildDatabaseAgentPrompt(workspaceId, agent, prompt, history ?? []), workingDir, {
|
|
86
|
+
maxTurns: 60,
|
|
87
|
+
functionTools,
|
|
88
|
+
mcpServers: {},
|
|
89
|
+
skills: [],
|
|
90
|
+
sandboxDirs: [],
|
|
91
|
+
outputStyle: agent.outputStyle,
|
|
92
|
+
});
|
|
93
|
+
const finalMessage = result.success
|
|
94
|
+
? extractFinalMessage(result.output, result.summary)
|
|
95
|
+
: result.error || extractFinalMessage(result.output, result.summary);
|
|
96
|
+
res.status(result.success ? 200 : 400).json({ finalMessage });
|
|
97
|
+
});
|
|
98
|
+
router.get('/databases', (req, res) => {
|
|
99
|
+
const databases = store.listDatabases(wid(req));
|
|
100
|
+
res.json(databases.length > 0 ? databases : [store.getDefaultDatabase(wid(req))]);
|
|
101
|
+
});
|
|
102
|
+
router.post('/databases', (req, res) => {
|
|
103
|
+
const database = store.createDatabase(wid(req), req.body);
|
|
104
|
+
res.status(201).json(database);
|
|
105
|
+
});
|
|
106
|
+
router.put('/databases/:databaseId', (req, res) => {
|
|
107
|
+
const database = store.updateDatabase(wid(req), req.params.databaseId, req.body);
|
|
108
|
+
if (!database)
|
|
109
|
+
return res.status(404).json({ error: 'Database not found' });
|
|
110
|
+
res.json(database);
|
|
111
|
+
});
|
|
112
|
+
router.get('/databases/:databaseId/vector', (req, res) => {
|
|
113
|
+
if (!store.getDatabase(wid(req), req.params.databaseId)) {
|
|
114
|
+
return res.status(404).json({ error: 'Database not found' });
|
|
115
|
+
}
|
|
116
|
+
res.json(store.getVectorStats(wid(req), req.params.databaseId));
|
|
117
|
+
});
|
|
118
|
+
router.put('/databases/:databaseId/vector', (req, res) => {
|
|
119
|
+
const { embeddingModelId } = req.body;
|
|
120
|
+
const database = store.setDatabaseEmbeddingModel(wid(req), req.params.databaseId, embeddingModelId || null);
|
|
121
|
+
if (!database)
|
|
122
|
+
return res.status(404).json({ error: 'Database not found' });
|
|
123
|
+
res.json(store.getVectorStats(wid(req), req.params.databaseId));
|
|
124
|
+
});
|
|
125
|
+
router.post('/databases/:databaseId/vector/index', async (req, res) => {
|
|
126
|
+
try {
|
|
127
|
+
res.json(await databaseVector.indexDatabaseVectors(wid(req), req.params.databaseId));
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
console.error('[database:vector:index] failed', {
|
|
131
|
+
workspaceId: wid(req),
|
|
132
|
+
databaseId: req.params.databaseId,
|
|
133
|
+
error: error instanceof Error ? error.message : String(error),
|
|
134
|
+
debug: error instanceof databaseVector.DatabaseVectorError ? error.debug : undefined,
|
|
135
|
+
});
|
|
136
|
+
res.status(400).json({
|
|
137
|
+
error: error instanceof Error ? error.message : String(error),
|
|
138
|
+
debug: error instanceof databaseVector.DatabaseVectorError ? error.debug : undefined,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
router.delete('/databases/:databaseId', (req, res) => {
|
|
143
|
+
if (!store.deleteDatabase(wid(req), req.params.databaseId)) {
|
|
144
|
+
return res.status(404).json({ error: 'Database not found' });
|
|
145
|
+
}
|
|
146
|
+
res.json({ ok: true });
|
|
147
|
+
});
|
|
148
|
+
// List all nodes
|
|
149
|
+
router.get('/', (req, res) => {
|
|
150
|
+
res.json(store.listNodes(wid(req), databaseId(req)));
|
|
151
|
+
});
|
|
152
|
+
// Get single node
|
|
153
|
+
router.get('/:nodeId', (req, res) => {
|
|
154
|
+
const node = store.getNode(wid(req), req.params.nodeId, databaseId(req));
|
|
155
|
+
if (!node)
|
|
156
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
157
|
+
res.json(node);
|
|
158
|
+
});
|
|
159
|
+
router.get('/:nodeId/versions', (req, res) => {
|
|
160
|
+
flushPendingContentSave(wid(req), databaseId(req), req.params.nodeId);
|
|
161
|
+
const limit = typeof req.query.limit === 'string' ? Number(req.query.limit) : 50;
|
|
162
|
+
const versions = store.listNodeVersions(wid(req), req.params.nodeId, databaseId(req), limit);
|
|
163
|
+
res.json(versions);
|
|
164
|
+
});
|
|
165
|
+
// Create node
|
|
166
|
+
router.post('/', (req, res) => {
|
|
167
|
+
const node = store.createNode(wid(req), { ...req.body, databaseId: databaseId(req) });
|
|
168
|
+
res.status(201).json(node);
|
|
169
|
+
});
|
|
170
|
+
// Update node
|
|
171
|
+
router.put('/:nodeId', (req, res) => {
|
|
172
|
+
const workspaceId = wid(req);
|
|
173
|
+
const activeDatabaseId = databaseId(req);
|
|
174
|
+
const nodeId = req.params.nodeId;
|
|
175
|
+
const body = req.body;
|
|
176
|
+
const { content, ...metadataUpdates } = body;
|
|
177
|
+
let node = Object.keys(metadataUpdates).length > 0
|
|
178
|
+
? store.updateNode(workspaceId, nodeId, metadataUpdates, activeDatabaseId)
|
|
179
|
+
: store.getNode(workspaceId, nodeId, activeDatabaseId);
|
|
180
|
+
if (!node)
|
|
181
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
182
|
+
if (typeof content === 'string') {
|
|
183
|
+
scheduleContentSave(workspaceId, activeDatabaseId, nodeId, content);
|
|
184
|
+
node = { ...node, content, updatedAt: Date.now() };
|
|
185
|
+
}
|
|
186
|
+
res.json(node);
|
|
187
|
+
});
|
|
188
|
+
// Move node (change parent)
|
|
189
|
+
router.put('/:nodeId/move', (req, res) => {
|
|
190
|
+
const { parentId } = req.body;
|
|
191
|
+
const node = store.moveNode(wid(req), req.params.nodeId, parentId ?? null, databaseId(req));
|
|
192
|
+
if (!node)
|
|
193
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
194
|
+
res.json(node);
|
|
195
|
+
});
|
|
196
|
+
// Trash node (soft delete)
|
|
197
|
+
router.put('/:nodeId/trash', (req, res) => {
|
|
198
|
+
const node = store.trashNode(wid(req), req.params.nodeId, databaseId(req));
|
|
199
|
+
if (!node)
|
|
200
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
201
|
+
res.json(node);
|
|
202
|
+
});
|
|
203
|
+
// Restore node from trash
|
|
204
|
+
router.put('/:nodeId/restore', (req, res) => {
|
|
205
|
+
const node = store.restoreNode(wid(req), req.params.nodeId, databaseId(req));
|
|
206
|
+
if (!node)
|
|
207
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
208
|
+
res.json(node);
|
|
209
|
+
});
|
|
210
|
+
// Delete node permanently
|
|
211
|
+
router.delete('/:nodeId', (req, res) => {
|
|
212
|
+
if (!store.deleteNode(wid(req), req.params.nodeId, databaseId(req))) {
|
|
213
|
+
return res.status(404).json({ error: 'Node not found' });
|
|
214
|
+
}
|
|
215
|
+
res.json({ ok: true });
|
|
216
|
+
});
|
|
217
|
+
function scheduleContentSave(workspaceId, activeDatabaseId, nodeId, content) {
|
|
218
|
+
const key = `${workspaceId}:${activeDatabaseId}:${nodeId}`;
|
|
219
|
+
const existing = pendingContentSaves.get(key);
|
|
220
|
+
if (existing)
|
|
221
|
+
clearTimeout(existing.timer);
|
|
222
|
+
const timer = setTimeout(() => {
|
|
223
|
+
flushPendingContentSave(workspaceId, activeDatabaseId, nodeId);
|
|
224
|
+
}, CONTENT_SAVE_IDLE_MS);
|
|
225
|
+
pendingContentSaves.set(key, { timer, content });
|
|
226
|
+
}
|
|
227
|
+
function flushPendingContentSave(workspaceId, activeDatabaseId, nodeId) {
|
|
228
|
+
const key = `${workspaceId}:${activeDatabaseId}:${nodeId}`;
|
|
229
|
+
const pending = pendingContentSaves.get(key);
|
|
230
|
+
if (!pending)
|
|
231
|
+
return;
|
|
232
|
+
clearTimeout(pending.timer);
|
|
233
|
+
pendingContentSaves.delete(key);
|
|
234
|
+
store.updateNode(workspaceId, nodeId, { content: pending.content }, activeDatabaseId);
|
|
235
|
+
}
|
|
236
|
+
function databaseAgentPath(workspaceId) {
|
|
237
|
+
return join(getDataDir(), 'workspaces', workspaceId, 'database', 'agent.json');
|
|
238
|
+
}
|
|
239
|
+
function readDatabaseAgent(workspaceId) {
|
|
240
|
+
const filePath = databaseAgentPath(workspaceId);
|
|
241
|
+
if (!existsSync(filePath))
|
|
242
|
+
return defaultDatabaseAgent();
|
|
243
|
+
try {
|
|
244
|
+
return normalizeDatabaseAgent(JSON.parse(readFileSync(filePath, 'utf-8')));
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return defaultDatabaseAgent();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
function writeDatabaseAgent(workspaceId, input) {
|
|
251
|
+
const agent = normalizeDatabaseAgent(input);
|
|
252
|
+
ensureDir(join(getDataDir(), 'workspaces', workspaceId, 'database'));
|
|
253
|
+
writeFileSync(databaseAgentPath(workspaceId), JSON.stringify(agent, null, 2), 'utf-8');
|
|
254
|
+
return agent;
|
|
255
|
+
}
|
|
256
|
+
function defaultDatabaseAgent() {
|
|
257
|
+
return normalizeDatabaseAgent({
|
|
258
|
+
name: 'Database AI',
|
|
259
|
+
role: 'agent',
|
|
260
|
+
description: 'Knowledge base assistant for Agent Spaces database documents.',
|
|
261
|
+
runtimeKind: 'claude-code',
|
|
262
|
+
modelProvider: undefined,
|
|
263
|
+
modelId: '',
|
|
264
|
+
apiBase: '',
|
|
265
|
+
apiKey: '',
|
|
266
|
+
systemPrompt: [
|
|
267
|
+
'You are the database knowledge base assistant.',
|
|
268
|
+
'Answer from Agent Spaces database content when possible.',
|
|
269
|
+
'Use only the provided database tools for knowledge base operations.',
|
|
270
|
+
'Return only the final answer in concise Markdown.',
|
|
271
|
+
].join('\n'),
|
|
272
|
+
temperature: 0.2,
|
|
273
|
+
maxTokens: 4096,
|
|
274
|
+
enabled: true,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
function normalizeDatabaseAgent(input) {
|
|
278
|
+
return {
|
|
279
|
+
id: DATABASE_AGENT_ID,
|
|
280
|
+
name: input.name?.trim() || 'Database AI',
|
|
281
|
+
role: 'agent',
|
|
282
|
+
description: input.description || '',
|
|
283
|
+
runtimeKind: input.runtimeKind || 'claude-code',
|
|
284
|
+
modelProvider: input.modelProvider,
|
|
285
|
+
modelId: input.modelId || '',
|
|
286
|
+
apiBase: input.apiBase || '',
|
|
287
|
+
apiKey: input.apiKey || '',
|
|
288
|
+
workingDir: '',
|
|
289
|
+
mcps: {},
|
|
290
|
+
skills: [],
|
|
291
|
+
tools: DATABASE_AGENT_TOOLS,
|
|
292
|
+
systemPrompt: input.systemPrompt || defaultDatabaseAgent().systemPrompt,
|
|
293
|
+
outputStyle: input.outputStyle,
|
|
294
|
+
temperature: input.temperature ?? 0.2,
|
|
295
|
+
maxTokens: input.maxTokens ?? 4096,
|
|
296
|
+
sandboxDirs: [],
|
|
297
|
+
maxRetries: input.maxRetries,
|
|
298
|
+
enabled: input.enabled ?? true,
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function buildDatabaseAgentPrompt(workspaceId, agent, userMessage, history) {
|
|
302
|
+
const recentHistory = history
|
|
303
|
+
.slice(-12)
|
|
304
|
+
.map((item) => `${item.role === 'user' ? 'User' : 'Agent'}: ${item.content}`)
|
|
305
|
+
.join('\n\n');
|
|
306
|
+
return [
|
|
307
|
+
agent.systemPrompt?.trim(),
|
|
308
|
+
'Runtime constraints:',
|
|
309
|
+
`- Current workspace id: ${workspaceId}`,
|
|
310
|
+
'- MCP servers configured for this agent: none.',
|
|
311
|
+
`- Available database tools: ${DATABASE_AGENT_TOOLS.map((tool) => `mcp__agent-spaces__${tool}`).join(', ')}.`,
|
|
312
|
+
'- Use mcp__agent-spaces__ListDatabases when you need to know valid database IDs.',
|
|
313
|
+
'- If the user does not specify a database, omit databaseId and the first database will be used automatically.',
|
|
314
|
+
'- Never use the workspace id as databaseId.',
|
|
315
|
+
'- Do not use filesystem, command, issue, channel, web, or other non-database tools for knowledge base work.',
|
|
316
|
+
'- If you need database content, call the database tools before answering.',
|
|
317
|
+
'- Return only the final answer in Markdown. Do not include tool logs or implementation traces.',
|
|
318
|
+
recentHistory ? `Conversation history:\n${recentHistory}` : '',
|
|
319
|
+
`User message:\n${userMessage}`,
|
|
320
|
+
].filter(Boolean).join('\n\n');
|
|
321
|
+
}
|
|
322
|
+
function extractFinalMessage(output, fallback) {
|
|
323
|
+
const candidates = output
|
|
324
|
+
.map((line) => line.trim())
|
|
325
|
+
.filter((line) => {
|
|
326
|
+
if (!line)
|
|
327
|
+
return false;
|
|
328
|
+
if (/^\[Usage\]/i.test(line))
|
|
329
|
+
return false;
|
|
330
|
+
if (/^(Tool:|Todo:|Codex initialized\b|Claude Code initialized\b)/i.test(line))
|
|
331
|
+
return false;
|
|
332
|
+
if (/^\[Reasoning\]/i.test(line))
|
|
333
|
+
return false;
|
|
334
|
+
return true;
|
|
335
|
+
});
|
|
336
|
+
return candidates.at(-1) || fallback || '';
|
|
337
|
+
}
|
|
338
|
+
function getRuntimeBaseURL(provider, apiBase) {
|
|
339
|
+
if (provider === 'openai-responses-to-anthropic-messages'
|
|
340
|
+
|| provider === 'openai-chat-completions-to-anthropic-messages')
|
|
341
|
+
return undefined;
|
|
342
|
+
return apiBase;
|
|
343
|
+
}
|
|
344
|
+
export default router;
|
|
345
|
+
//# sourceMappingURL=database.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, gitGetRemotes, gitAddRemote, gitCheckoutDetached, gitCherryPick, gitCreateBranch, gitDeleteBranch, gitCreateTag, gitCommitDiff, gitGetRemoteUrl, gitMergeBase, gitGetConfig, gitSetConfig } 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 } from '../adapters/git.js';
|
|
3
3
|
const router = Router({ mergeParams: true });
|
|
4
4
|
router.get('/status', async (req, res) => {
|
|
5
5
|
try {
|
|
@@ -67,6 +67,48 @@ router.post('/discard-all', async (req, res) => {
|
|
|
67
67
|
res.status(500).json({ error: err.message });
|
|
68
68
|
}
|
|
69
69
|
});
|
|
70
|
+
router.post('/stage', async (req, res) => {
|
|
71
|
+
try {
|
|
72
|
+
const { path } = req.body;
|
|
73
|
+
if (!path) {
|
|
74
|
+
res.status(400).json({ error: 'path is required' });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
await gitStage(req.params.id, path);
|
|
78
|
+
res.json({ ok: true });
|
|
79
|
+
}
|
|
80
|
+
catch (err) {
|
|
81
|
+
res.status(500).json({ error: err.message });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
router.post('/unstage', async (req, res) => {
|
|
85
|
+
try {
|
|
86
|
+
const { path } = req.body;
|
|
87
|
+
if (!path) {
|
|
88
|
+
res.status(400).json({ error: 'path is required' });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
await gitUnstage(req.params.id, path);
|
|
92
|
+
res.json({ ok: true });
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
res.status(500).json({ error: err.message });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
router.post('/resolve-file', async (req, res) => {
|
|
99
|
+
try {
|
|
100
|
+
const { path, content, stage } = req.body;
|
|
101
|
+
if (!path || typeof content !== 'string') {
|
|
102
|
+
res.status(400).json({ error: 'path and content are required' });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
await gitResolveFile(req.params.id, path, content, stage !== false);
|
|
106
|
+
res.json({ ok: true });
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
res.status(500).json({ error: err.message });
|
|
110
|
+
}
|
|
111
|
+
});
|
|
70
112
|
router.get('/branches', async (req, res) => {
|
|
71
113
|
try {
|
|
72
114
|
const result = await gitBranches(req.params.id);
|
|
@@ -108,6 +150,15 @@ router.post('/generate-commit-message', async (req, res) => {
|
|
|
108
150
|
res.status(500).json({ error: err.message });
|
|
109
151
|
}
|
|
110
152
|
});
|
|
153
|
+
router.post('/fetch', async (req, res) => {
|
|
154
|
+
try {
|
|
155
|
+
await gitFetch(req.params.id);
|
|
156
|
+
res.json({ ok: true });
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
res.status(500).json({ error: err.message });
|
|
160
|
+
}
|
|
161
|
+
});
|
|
111
162
|
router.post('/push', async (req, res) => {
|
|
112
163
|
try {
|
|
113
164
|
await gitPush(req.params.id);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import * as svc from '../services/kanban.js';
|
|
3
|
+
const router = Router({ mergeParams: true });
|
|
4
|
+
// GET /api/workspaces/:id/kanban — 获取或初始化 board
|
|
5
|
+
router.get('/', (req, res) => {
|
|
6
|
+
const workspaceId = req.params.id;
|
|
7
|
+
if (!workspaceId) {
|
|
8
|
+
res.status(400).json({ error: 'workspaceId required' });
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const board = svc.ensureBoard(workspaceId);
|
|
13
|
+
res.json(board);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
res.status(500).json({ error: error.message });
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
// PUT /api/workspaces/:id/kanban — 保存完整 board 状态
|
|
20
|
+
router.put('/', (req, res) => {
|
|
21
|
+
const workspaceId = req.params.id;
|
|
22
|
+
if (!workspaceId) {
|
|
23
|
+
res.status(400).json({ error: 'workspaceId required' });
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const board = svc.saveBoard(workspaceId, req.body);
|
|
28
|
+
if (!board) {
|
|
29
|
+
res.status(404).json({ error: 'Board not found' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
res.json(board);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
res.status(400).json({ error: error.message });
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
export default router;
|
|
39
|
+
//# sourceMappingURL=kanban.js.map
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, writeFileSync, unlinkSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { getDataDir, ensureDir } from '../storage/json-store.js';
|
|
4
|
+
function getAgentTemplatesDir() {
|
|
5
|
+
return join(getDataDir(), 'agent-templates');
|
|
6
|
+
}
|
|
7
|
+
function getCommandsDir(agentId) {
|
|
8
|
+
return join(getAgentTemplatesDir(), agentId, 'commands');
|
|
9
|
+
}
|
|
10
|
+
function getAgentName(agentId) {
|
|
11
|
+
const agentPath = join(getAgentTemplatesDir(), agentId, 'agent.json');
|
|
12
|
+
if (!existsSync(agentPath))
|
|
13
|
+
return undefined;
|
|
14
|
+
try {
|
|
15
|
+
const config = JSON.parse(readFileSync(agentPath, 'utf-8'));
|
|
16
|
+
return config.name || agentId;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return agentId;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function readCommandsFromDir(dir, agentId, group = '') {
|
|
23
|
+
if (!existsSync(dir))
|
|
24
|
+
return [];
|
|
25
|
+
const agentName = getAgentName(agentId);
|
|
26
|
+
return readdirSync(dir, { withFileTypes: true })
|
|
27
|
+
.flatMap((entry) => {
|
|
28
|
+
if (entry.isDirectory()) {
|
|
29
|
+
return readCommandsFromDir(join(dir, entry.name), agentId, entry.name);
|
|
30
|
+
}
|
|
31
|
+
if (!entry.name.endsWith('.md'))
|
|
32
|
+
return [];
|
|
33
|
+
return {
|
|
34
|
+
name: entry.name.replace(/\.md$/, ''),
|
|
35
|
+
content: readFileSync(join(dir, entry.name), 'utf-8'),
|
|
36
|
+
group,
|
|
37
|
+
agentId,
|
|
38
|
+
agentName,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
export function listAgentsWithCommands() {
|
|
43
|
+
const templatesDir = getAgentTemplatesDir();
|
|
44
|
+
if (!existsSync(templatesDir))
|
|
45
|
+
return [];
|
|
46
|
+
return readdirSync(templatesDir, { withFileTypes: true })
|
|
47
|
+
.filter((entry) => entry.isDirectory())
|
|
48
|
+
.map((entry) => {
|
|
49
|
+
const commandsDir = getCommandsDir(entry.name);
|
|
50
|
+
const commands = readCommandsFromDir(commandsDir, entry.name);
|
|
51
|
+
return {
|
|
52
|
+
agentId: entry.name,
|
|
53
|
+
agentName: getAgentName(entry.name) || entry.name,
|
|
54
|
+
commandCount: commands.length,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export function listAllCommands() {
|
|
59
|
+
const templatesDir = getAgentTemplatesDir();
|
|
60
|
+
if (!existsSync(templatesDir))
|
|
61
|
+
return [];
|
|
62
|
+
return readdirSync(templatesDir, { withFileTypes: true })
|
|
63
|
+
.filter((entry) => entry.isDirectory())
|
|
64
|
+
.flatMap((entry) => {
|
|
65
|
+
const commandsDir = getCommandsDir(entry.name);
|
|
66
|
+
return readCommandsFromDir(commandsDir, entry.name);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
export function listCommands(agentId) {
|
|
70
|
+
return readCommandsFromDir(getCommandsDir(agentId), agentId);
|
|
71
|
+
}
|
|
72
|
+
function resolveCommandPath(agentId, name, group) {
|
|
73
|
+
if (group) {
|
|
74
|
+
return join(getCommandsDir(agentId), group, `${name}.md`);
|
|
75
|
+
}
|
|
76
|
+
return join(getCommandsDir(agentId), `${name}.md`);
|
|
77
|
+
}
|
|
78
|
+
function findCommandPath(agentId, name, group) {
|
|
79
|
+
if (group) {
|
|
80
|
+
const p = join(getCommandsDir(agentId), group, `${name}.md`);
|
|
81
|
+
return existsSync(p) ? p : null;
|
|
82
|
+
}
|
|
83
|
+
// Search root first, then subdirectories
|
|
84
|
+
const root = join(getCommandsDir(agentId), `${name}.md`);
|
|
85
|
+
if (existsSync(root))
|
|
86
|
+
return root;
|
|
87
|
+
if (existsSync(getCommandsDir(agentId))) {
|
|
88
|
+
for (const entry of readdirSync(getCommandsDir(agentId), { withFileTypes: true })) {
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
const p = join(getCommandsDir(agentId), entry.name, `${name}.md`);
|
|
91
|
+
if (existsSync(p))
|
|
92
|
+
return p;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
export function getCommand(agentId, name, group) {
|
|
99
|
+
const filePath = findCommandPath(agentId, name, group);
|
|
100
|
+
if (!filePath)
|
|
101
|
+
return null;
|
|
102
|
+
// Infer group from path
|
|
103
|
+
const commandsDir = getCommandsDir(agentId);
|
|
104
|
+
const relative = filePath.slice(commandsDir.length + 1);
|
|
105
|
+
const parts = relative.split('/');
|
|
106
|
+
const inferredGroup = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
|
107
|
+
return {
|
|
108
|
+
name,
|
|
109
|
+
content: readFileSync(filePath, 'utf-8'),
|
|
110
|
+
group: inferredGroup,
|
|
111
|
+
agentId,
|
|
112
|
+
agentName: getAgentName(agentId),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
export function createCommand(agentId, name, content, group) {
|
|
116
|
+
const dir = group ? join(getCommandsDir(agentId), group) : getCommandsDir(agentId);
|
|
117
|
+
ensureDir(dir);
|
|
118
|
+
const filePath = join(dir, `${name}.md`);
|
|
119
|
+
writeFileSync(filePath, content, 'utf-8');
|
|
120
|
+
return {
|
|
121
|
+
name,
|
|
122
|
+
content,
|
|
123
|
+
group: group || '',
|
|
124
|
+
agentId,
|
|
125
|
+
agentName: getAgentName(agentId),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export function updateCommand(agentId, name, content, group) {
|
|
129
|
+
const filePath = findCommandPath(agentId, name, group);
|
|
130
|
+
if (!filePath)
|
|
131
|
+
return null;
|
|
132
|
+
writeFileSync(filePath, content, 'utf-8');
|
|
133
|
+
const commandsDir = getCommandsDir(agentId);
|
|
134
|
+
const relative = filePath.slice(commandsDir.length + 1);
|
|
135
|
+
const parts = relative.split('/');
|
|
136
|
+
const inferredGroup = parts.length > 1 ? parts.slice(0, -1).join('/') : '';
|
|
137
|
+
return {
|
|
138
|
+
name,
|
|
139
|
+
content,
|
|
140
|
+
group: inferredGroup,
|
|
141
|
+
agentId,
|
|
142
|
+
agentName: getAgentName(agentId),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
export function deleteCommand(agentId, name, group) {
|
|
146
|
+
const filePath = findCommandPath(agentId, name, group);
|
|
147
|
+
if (!filePath)
|
|
148
|
+
return false;
|
|
149
|
+
unlinkSync(filePath);
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
export function applyCommandToAgents(sourceAgentId, name, group, targetAgentIds) {
|
|
153
|
+
const src = getCommand(sourceAgentId, name, group);
|
|
154
|
+
if (!src)
|
|
155
|
+
return 0;
|
|
156
|
+
let applied = 0;
|
|
157
|
+
for (const targetId of targetAgentIds) {
|
|
158
|
+
if (targetId === sourceAgentId)
|
|
159
|
+
continue;
|
|
160
|
+
try {
|
|
161
|
+
createCommand(targetId, src.name, src.content);
|
|
162
|
+
applied++;
|
|
163
|
+
}
|
|
164
|
+
catch { /* skip */ }
|
|
165
|
+
}
|
|
166
|
+
return applied;
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=agent-commands.js.map
|