@agent-spaces/server 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/claude-code-runtime/index.js +48 -6
- package/dist/adapters/claude-code-runtime/message-format.js +3 -3
- package/dist/adapters/git.js +140 -2
- package/dist/agents/agent-designer.js +334 -0
- package/dist/agents/agent-message-parts.js +8 -0
- package/dist/agents/commit-agent.js +9 -2
- package/dist/agents/issue-task-controller.js +14 -4
- package/dist/app.js +53 -1
- package/dist/package.json +1 -1
- package/dist/routes/agent-sse.js +4 -1
- package/dist/routes/agent.js +15 -0
- package/dist/routes/channel.js +1 -1
- package/dist/routes/file.js +97 -1
- package/dist/routes/git.js +122 -1
- package/dist/routes/iframe-bookmarks.js +33 -0
- package/dist/routes/speech-recognition.js +80 -0
- package/dist/services/agent.js +48 -5
- package/dist/services/builtin-tools.js +67 -1
- package/dist/services/channel.js +2 -0
- package/dist/services/command-process-manager.js +14 -1
- package/dist/services/file.js +86 -6
- package/dist/services/gitignore.js +65 -0
- package/dist/services/issue-retry.js +2 -1
- package/dist/services/issue.js +2 -2
- package/dist/services/notification-hub/bot-agent.js +9 -1
- package/dist/services/persistent-agent-context.js +155 -0
- package/dist/services/pty.js +47 -2
- package/dist/services/search.js +11 -3
- package/dist/services/speech-recognition/base.js +3 -0
- package/dist/services/speech-recognition/index.js +16 -0
- package/dist/services/speech-recognition/tencent.js +112 -0
- package/dist/storage/iframe-bookmarks-store.js +46 -0
- package/dist/storage/speech-recognition-store.js +58 -0
- package/dist/web/404.html +1 -1
- package/dist/web/__next.__PAGE__.txt +4 -4
- package/dist/web/__next._full.txt +31 -26
- package/dist/web/__next._head.txt +4 -4
- package/dist/web/__next._index.txt +17 -13
- package/dist/web/__next._tree.txt +2 -2
- package/dist/web/_next/static/chunks/0-mtp2au0a0nh.js +189 -0
- package/dist/web/_next/static/chunks/00amm3dvu3po9.js +31 -0
- package/dist/web/_next/static/chunks/02unyp1obddyn.js +3 -0
- package/dist/web/_next/static/chunks/0d.v1csiyl.1~.js +2 -0
- package/dist/web/_next/static/chunks/0egot8y~i-ge3.js +1 -0
- package/dist/web/_next/static/chunks/0e~0o6v_awcod.js +1 -0
- package/dist/web/_next/static/chunks/0fpf.rso9mhc0.js +1 -0
- package/dist/web/_next/static/chunks/0glol5jdarfma.js +2 -0
- package/dist/web/_next/static/chunks/0m1ud--um8kjh.js +1 -0
- package/dist/web/_next/static/chunks/0o6w-uw2p.phy.js +5 -0
- package/dist/web/_next/static/chunks/0os7q6w~-tmg7.css +1 -0
- package/dist/web/_next/static/chunks/0plreh4_gkxf9.js +1 -0
- package/dist/web/_next/static/chunks/0u7_qd9hzqwac.js +1 -0
- package/dist/web/_next/static/chunks/0vesz93a98px4.js +1 -0
- package/dist/web/_next/static/chunks/0w3o.7vi.dlm6.js +1 -0
- package/dist/web/_next/static/chunks/0xtmr0y4vo-~p.js +1 -0
- package/dist/web/_next/static/chunks/0~3uikgc074il.js +1 -0
- package/dist/web/_next/static/chunks/{0y5ipuqgqfrob.js → 0~xn0gfqxa20r.js} +3 -3
- package/dist/web/_next/static/chunks/11ozf700niy2z.js +1 -0
- package/dist/web/_next/static/chunks/{0jmsjlawtg6oa.js → 145gbwitjxamg.js} +1 -1
- package/dist/web/_next/static/chunks/{turbopack-0lxiiw.jhevml.js → turbopack-0kcwat8.leugk.js} +1 -1
- package/dist/web/_not-found/__next._full.txt +34 -30
- package/dist/web/_not-found/__next._head.txt +4 -4
- package/dist/web/_not-found/__next._index.txt +17 -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 +34 -30
- package/dist/web/index.html +1 -1
- package/dist/web/index.txt +31 -26
- package/dist/web/login/__next._full.txt +35 -29
- package/dist/web/login/__next._head.txt +4 -4
- package/dist/web/login/__next._index.txt +17 -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 +35 -29
- package/dist/web/settings/__next._full.txt +36 -34
- package/dist/web/settings/__next._head.txt +4 -4
- package/dist/web/settings/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings/agents/__next._head.txt +4 -4
- package/dist/web/settings/agents/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings/mcps/__next._full.txt +38 -35
- package/dist/web/settings/mcps/__next._head.txt +4 -4
- package/dist/web/settings/mcps/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings/models/__next._full.txt +38 -35
- package/dist/web/settings/models/__next._head.txt +4 -4
- package/dist/web/settings/models/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings/providers/__next._full.txt +38 -35
- package/dist/web/settings/providers/__next._head.txt +4 -4
- package/dist/web/settings/providers/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings/skills/__next._full.txt +38 -35
- package/dist/web/settings/skills/__next._head.txt +4 -4
- package/dist/web/settings/skills/__next._index.txt +17 -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 +38 -35
- package/dist/web/settings.html +1 -1
- package/dist/web/settings.txt +36 -34
- package/dist/web/workflows/__next._full.txt +36 -31
- package/dist/web/workflows/__next._head.txt +4 -4
- package/dist/web/workflows/__next._index.txt +17 -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 +36 -31
- package/dist/web/workspace/_/__next._full.txt +39 -34
- package/dist/web/workspace/_/__next._head.txt +4 -4
- package/dist/web/workspace/_/__next._index.txt +17 -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 +39 -34
- package/dist/web/workspaces/__next._full.txt +35 -30
- package/dist/web/workspaces/__next._head.txt +4 -4
- package/dist/web/workspaces/__next._index.txt +17 -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 +35 -30
- package/dist/ws/agent-prompt.js +48 -18
- package/dist/ws/agent-runner.js +4 -1
- package/dist/ws/message-parts.js +8 -0
- package/dist/ws/terminal-handler.js +1 -1
- package/package.json +1 -1
- package/public/avatars/1778953228323-5je54x-user.jpg +0 -0
- package/public/avatars/1778954057880-g01q6y-user.jpg +0 -0
- package/dist/web/_next/static/chunks/002-dxhags4dj.js +0 -2
- package/dist/web/_next/static/chunks/00fu7sjtftd3f.js +0 -1
- package/dist/web/_next/static/chunks/00s_1ft2-qz0r.js +0 -1
- package/dist/web/_next/static/chunks/02wkg1tjv~_t2.js +0 -1
- package/dist/web/_next/static/chunks/03jy~o.gx._e-.js +0 -3
- package/dist/web/_next/static/chunks/07bs5ds68tg38.js +0 -2
- package/dist/web/_next/static/chunks/0b1w9_ne4c2ez.js +0 -1
- package/dist/web/_next/static/chunks/0bzechrx76-ix.js +0 -1
- package/dist/web/_next/static/chunks/0csqa76ud3h4d.js +0 -1
- package/dist/web/_next/static/chunks/0fxdvo63ywaa~.js +0 -1
- package/dist/web/_next/static/chunks/0k5bmi-es-2nj.js +0 -1
- package/dist/web/_next/static/chunks/0pep4mkvt3.rh.js +0 -31
- package/dist/web/_next/static/chunks/0tqwdxb-8t_n1.js +0 -1
- package/dist/web/_next/static/chunks/0yc41k980zabo.js +0 -1
- package/dist/web/_next/static/chunks/0zhhkzv4.0koq.js +0 -183
- package/dist/web/_next/static/chunks/0zl19l5tuoppw.js +0 -1
- package/dist/web/_next/static/chunks/102lz3yanx8i~.css +0 -1
- package/dist/web/_next/static/chunks/13wm9.vry~.lh.js +0 -5
- /package/dist/web/_next/static/{XzP71HbFE1fuE_bLT-x7i → 4dBAEZ275uRqcyeaRmXSx}/_buildManifest.js +0 -0
- /package/dist/web/_next/static/{XzP71HbFE1fuE_bLT-x7i → 4dBAEZ275uRqcyeaRmXSx}/_clientMiddlewareManifest.js +0 -0
- /package/dist/web/_next/static/{XzP71HbFE1fuE_bLT-x7i → 4dBAEZ275uRqcyeaRmXSx}/_ssgManifest.js +0 -0
|
@@ -7,6 +7,7 @@ import * as workspaceService from '../services/workspace.js';
|
|
|
7
7
|
import { mapWorkflowToTaskDrafts, validateWorkflowForRun } from '../services/workflow.js';
|
|
8
8
|
import { createIssueFunctionTools } from '../services/builtin-tools.js';
|
|
9
9
|
import { getThinkingRuntimeConfig } from '../services/llm-model-config.js';
|
|
10
|
+
import { prependPersistentAgentContext } from '../services/persistent-agent-context.js';
|
|
10
11
|
import { completeIssueAgentProgress, createIssueAgentProgress, createIssueAgentProgressTracker } from './issue-agent-progress.js';
|
|
11
12
|
const ACTIVE_TASK_STATUSES = ['running', 'reviewing', 'retrying', 'waiting_review'];
|
|
12
13
|
export async function syncIssueTasksAfterPlanning(workspaceId, issueId, input, ctx) {
|
|
@@ -45,7 +46,7 @@ export async function syncIssueTasksAfterPlanning(workspaceId, issueId, input, c
|
|
|
45
46
|
},
|
|
46
47
|
});
|
|
47
48
|
const runtime = createRuntimeForPreset(taskSyncPreset);
|
|
48
|
-
const result = await runtime.execute(buildTaskSyncPrompt(issue, input, taskSyncWorkingDir), taskSyncWorkingDir, {
|
|
49
|
+
const result = await runtime.execute(buildIssueAgentPrompt(workspaceId, buildTaskSyncPrompt(issue, input, taskSyncWorkingDir), taskSyncWorkingDir, taskSyncPreset), taskSyncWorkingDir, {
|
|
49
50
|
maxTurns: 20,
|
|
50
51
|
mcpServers: undefined,
|
|
51
52
|
functionTools: createTaskSyncTools(workspaceId, issue, taskSyncPreset, ctx),
|
|
@@ -184,7 +185,7 @@ export async function runIssueTask(workspaceId, issueId, taskId, ctx) {
|
|
|
184
185
|
agentId: taskAgent.id,
|
|
185
186
|
data: `[debug] workflow agentConfigId=${taskAgentPreset.id} role=${taskAgentPreset.role} taskAgentConfigId=${runningTask.agentConfigId || '(fallback)'} runtime=${taskAgentPreset.runtimeKind ?? 'open-agent-sdk'}`,
|
|
186
187
|
});
|
|
187
|
-
const result = await runtime.execute(buildTaskAgentPrompt(issue, runningTask, taskAgentPreset, agentWorkingDir), agentWorkingDir, {
|
|
188
|
+
const result = await runtime.execute(buildIssueAgentPrompt(workspaceId, buildTaskAgentPrompt(issue, runningTask, taskAgentPreset, agentWorkingDir), agentWorkingDir, taskAgentPreset), agentWorkingDir, {
|
|
188
189
|
maxTurns: 100,
|
|
189
190
|
mcpServers: agentService.getMcpServers(taskAgentPreset.mcps),
|
|
190
191
|
functionTools: createCurrentIssueTools(workspaceId, issue, taskAgentPreset),
|
|
@@ -324,10 +325,10 @@ export function createTasksFromWorkflow(workspaceId, issueId, template, ctx) {
|
|
|
324
325
|
}
|
|
325
326
|
const drafts = mapWorkflowToTaskDrafts(template);
|
|
326
327
|
issueService.updateStatus(workspaceId, issueId, 'planned');
|
|
327
|
-
ctx.broadcast('issue.status_changed', { issueId,
|
|
328
|
+
ctx.broadcast('issue.status_changed', { issueId, from: issue.status, to: 'planned' });
|
|
328
329
|
replaceIssueTasksFromDrafts(workspaceId, issueId, ctx, drafts);
|
|
329
330
|
issueService.updateStatus(workspaceId, issueId, 'in_progress');
|
|
330
|
-
ctx.broadcast('issue.status_changed', { issueId,
|
|
331
|
+
ctx.broadcast('issue.status_changed', { issueId, from: 'planned', to: 'in_progress' });
|
|
331
332
|
ctx.broadcast('issue.updated', issueService.getById(workspaceId, issueId));
|
|
332
333
|
scheduleRunnableIssueTasks(workspaceId, issueId, ctx).catch((err) => {
|
|
333
334
|
console.error(`[workflow] task scheduling failed for issue ${issueId}:`, err);
|
|
@@ -435,6 +436,15 @@ function createRuntimeForPreset(preset) {
|
|
|
435
436
|
function resolveIssueWorkspaceRoot(workspaceId) {
|
|
436
437
|
return workspaceService.getById(workspaceId)?.boundDirs?.[0] || process.cwd();
|
|
437
438
|
}
|
|
439
|
+
function buildIssueAgentPrompt(workspaceId, prompt, workingDir, preset) {
|
|
440
|
+
return prependPersistentAgentContext(prompt, {
|
|
441
|
+
workspaceId,
|
|
442
|
+
workingDir,
|
|
443
|
+
boundDirs: workspaceService.getById(workspaceId)?.boundDirs,
|
|
444
|
+
includeWorkspacePrompt: false,
|
|
445
|
+
excludeNativeClaudeMd: preset.runtimeKind === 'claude-code',
|
|
446
|
+
});
|
|
447
|
+
}
|
|
438
448
|
function buildTaskSyncPrompt(issue, input, workingDir) {
|
|
439
449
|
return [
|
|
440
450
|
'You are the issue task synchronization controller.',
|
package/dist/app.js
CHANGED
|
@@ -27,6 +27,8 @@ import subscriptionRouter from './routes/subscription.js';
|
|
|
27
27
|
import agentSseRouter from './routes/agent-sse.js';
|
|
28
28
|
import searchRouter from './routes/search.js';
|
|
29
29
|
import notificationRouter from './routes/notification.js';
|
|
30
|
+
import iframeBookmarksRouter from './routes/iframe-bookmarks.js';
|
|
31
|
+
import speechRecognitionRouter, { handleSpeechStream } from './routes/speech-recognition.js';
|
|
30
32
|
import { getUserSettings, setUserAvatarUrl, removeUserAvatarUrl } from './storage/user-settings-store.js';
|
|
31
33
|
import { authMiddleware, verifyToken } from './middleware/auth.js';
|
|
32
34
|
import { handleConnection } from './ws/handler.js';
|
|
@@ -100,6 +102,27 @@ app.use('/api/workspaces/:id/commands', commandRouter);
|
|
|
100
102
|
app.use('/api/workspaces/:id/agents', agentRouter);
|
|
101
103
|
app.use('/api/workspaces/:id/tasks', taskRouter);
|
|
102
104
|
app.use('/api/workspaces/:id/git', gitRouter);
|
|
105
|
+
// Global git config (no workspace context needed)
|
|
106
|
+
import { gitGetConfig as _gitGetConfig, gitSetConfig as _gitSetConfig } from './adapters/git.js';
|
|
107
|
+
app.get('/api/git-config', async (_req, res) => {
|
|
108
|
+
try {
|
|
109
|
+
const config = await _gitGetConfig('global');
|
|
110
|
+
res.json(config);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
res.status(500).json({ error: err.message });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
app.post('/api/git-config', async (req, res) => {
|
|
117
|
+
try {
|
|
118
|
+
const { name, email, proxy } = req.body;
|
|
119
|
+
await _gitSetConfig('global', { name, email, proxy });
|
|
120
|
+
res.json({ ok: true });
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
res.status(500).json({ error: err.message });
|
|
124
|
+
}
|
|
125
|
+
});
|
|
103
126
|
app.use('/api/workspaces/:id/search', searchRouter);
|
|
104
127
|
app.use('/api/workspaces/:id/notifications', notificationRouter);
|
|
105
128
|
app.use('/api/agents', agentRouter);
|
|
@@ -108,6 +131,8 @@ app.use('/api/folder', folderRouter);
|
|
|
108
131
|
app.use('/api/skills', skillRouter);
|
|
109
132
|
app.use('/api/mcps', mcpRouter);
|
|
110
133
|
app.use('/api/subscriptions', subscriptionRouter);
|
|
134
|
+
app.use('/api/speech-recognition', speechRecognitionRouter);
|
|
135
|
+
app.use('/api/iframe-bookmarks', iframeBookmarksRouter);
|
|
111
136
|
// Serve static web frontend in production (after API routes, before catch-all)
|
|
112
137
|
const webDir = resolveRuntimeDir('web');
|
|
113
138
|
if (existsSync(webDir)) {
|
|
@@ -134,7 +159,18 @@ else {
|
|
|
134
159
|
console.warn('[server] web frontend not found at', webDir, '- run \`pnpm build\` first');
|
|
135
160
|
}
|
|
136
161
|
const server = createServer(app);
|
|
137
|
-
const wss = new WebSocketServer({
|
|
162
|
+
const wss = new WebSocketServer({ noServer: true });
|
|
163
|
+
// Speech recognition WebSocket on /ws/speech
|
|
164
|
+
const speechWss = new WebSocketServer({ noServer: true });
|
|
165
|
+
speechWss.on('connection', (ws, req) => {
|
|
166
|
+
const token = new URL(req.url || '', `http://localhost:${PORT}`).searchParams.get('token');
|
|
167
|
+
if (!verifyToken(token)) {
|
|
168
|
+
ws.close(4003, 'Unauthorized');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const configId = new URL(req.url || '', `http://localhost:${PORT}`).searchParams.get('configId') || undefined;
|
|
172
|
+
handleSpeechStream(ws, configId);
|
|
173
|
+
});
|
|
138
174
|
wss.on('connection', (ws, req) => {
|
|
139
175
|
const url = new URL(req.url || '', `http://localhost:${PORT}`);
|
|
140
176
|
const workspaceId = url.searchParams.get('workspaceId');
|
|
@@ -149,6 +185,22 @@ wss.on('connection', (ws, req) => {
|
|
|
149
185
|
}
|
|
150
186
|
handleConnection(ws, workspaceId);
|
|
151
187
|
});
|
|
188
|
+
server.on('upgrade', (req, socket, head) => {
|
|
189
|
+
const { pathname } = new URL(req.url || '/', `http://localhost:${PORT}`);
|
|
190
|
+
if (pathname === '/ws') {
|
|
191
|
+
wss.handleUpgrade(req, socket, head, (ws) => {
|
|
192
|
+
wss.emit('connection', ws, req);
|
|
193
|
+
});
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (pathname === '/ws/speech') {
|
|
197
|
+
speechWss.handleUpgrade(req, socket, head, (ws) => {
|
|
198
|
+
speechWss.emit('connection', ws, req);
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
socket.destroy();
|
|
203
|
+
});
|
|
152
204
|
const HOST = process.env.HOST || '0.0.0.0';
|
|
153
205
|
server.listen(PORT, HOST, () => {
|
|
154
206
|
console.log(`[server] listening on http://${HOST}:${PORT}`);
|
package/dist/package.json
CHANGED
package/dist/routes/agent-sse.js
CHANGED
|
@@ -45,6 +45,7 @@ router.post('/run', async (req, res) => {
|
|
|
45
45
|
const configDir = agentService.getAgentConfigDir(workspaceId, { ...preset, skills: requestedSkills });
|
|
46
46
|
const skills = agentService.getAvailableSkillNames(configDir, requestedSkills);
|
|
47
47
|
const output = [];
|
|
48
|
+
const workingDir = agentService.resolveWorkingDir(workspaceId, preset);
|
|
48
49
|
let completed = false;
|
|
49
50
|
prepareSse(res);
|
|
50
51
|
writeSse(res, 'session', { session, workspaceId });
|
|
@@ -68,8 +69,10 @@ router.post('/run', async (req, res) => {
|
|
|
68
69
|
mcpServers: Object.keys(mcpServers ?? {}),
|
|
69
70
|
skills,
|
|
70
71
|
boundDirs: workspace.boundDirs,
|
|
72
|
+
workingDir,
|
|
73
|
+
excludeNativeClaudeMd: preset.runtimeKind === 'claude-code',
|
|
71
74
|
builtInTools: [],
|
|
72
|
-
}),
|
|
75
|
+
}), workingDir, {
|
|
73
76
|
maxTurns: normalizeMaxTurns(body.maxTurns),
|
|
74
77
|
mcpServers,
|
|
75
78
|
skills,
|
package/dist/routes/agent.js
CHANGED
|
@@ -1,5 +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
4
|
const router = Router({ mergeParams: true });
|
|
4
5
|
router.get('/usage/dashboard', (req, res) => {
|
|
5
6
|
const days = Number(req.query.days ?? 30);
|
|
@@ -21,6 +22,20 @@ router.post('/presets', (req, res) => {
|
|
|
21
22
|
const preset = agentService.createPreset(req.params.id, body);
|
|
22
23
|
res.status(201).json(preset);
|
|
23
24
|
});
|
|
25
|
+
router.post('/presets/generate', async (req, res) => {
|
|
26
|
+
const { prompt } = req.body;
|
|
27
|
+
if (!prompt?.trim()) {
|
|
28
|
+
res.status(400).json({ error: 'prompt is required' });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
res.json(await generateAgentDesign(prompt));
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
console.error('[agent-designer] generate failed', err);
|
|
36
|
+
res.status(400).json({ error: err instanceof Error ? err.message : 'agent generation failed' });
|
|
37
|
+
}
|
|
38
|
+
});
|
|
24
39
|
router.post('/presets/test-connection', async (req, res) => {
|
|
25
40
|
const workspaceId = req.params.id;
|
|
26
41
|
const data = req.body;
|
package/dist/routes/channel.js
CHANGED
|
@@ -24,7 +24,7 @@ router.post('/', (req, res) => {
|
|
|
24
24
|
router.put('/:channelId', (req, res) => {
|
|
25
25
|
const { id, channelId } = req.params;
|
|
26
26
|
const patch = {};
|
|
27
|
-
for (const key of ['name', 'type', 'issueId', 'members', 'pinnedMentionId', 'draft', 'todos']) {
|
|
27
|
+
for (const key of ['name', 'type', 'issueId', 'members', 'pinnedMentionId', 'draft', 'todos', 'archived']) {
|
|
28
28
|
if (Object.hasOwn(req.body, key))
|
|
29
29
|
patch[key] = req.body[key];
|
|
30
30
|
}
|
package/dist/routes/file.js
CHANGED
|
@@ -12,7 +12,8 @@ router.get('/tree', async (req, res) => {
|
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
const path = req.query.path || '';
|
|
15
|
-
const
|
|
15
|
+
const depth = parseInt(req.query.depth) || undefined;
|
|
16
|
+
const tree = await fileService.readTree(ws, path, depth);
|
|
16
17
|
res.json(tree);
|
|
17
18
|
});
|
|
18
19
|
router.get('/content', async (req, res) => {
|
|
@@ -144,5 +145,100 @@ router.post('/reveal', async (req, res) => {
|
|
|
144
145
|
res.json({ ok: true, path: fullPath });
|
|
145
146
|
});
|
|
146
147
|
});
|
|
148
|
+
router.post('/rename', async (req, res) => {
|
|
149
|
+
const ws = fileService.getWorkspace(req.params.id);
|
|
150
|
+
if (!ws) {
|
|
151
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
const { oldPath, newPath } = req.body;
|
|
155
|
+
if (!oldPath || !newPath) {
|
|
156
|
+
res.status(400).json({ error: 'oldPath and newPath are required' });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const ok = await fileService.renamePath(ws, oldPath, newPath);
|
|
160
|
+
if (!ok) {
|
|
161
|
+
res.status(500).json({ error: 'Failed to rename' });
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
res.json({ ok: true });
|
|
165
|
+
});
|
|
166
|
+
router.post('/copy', async (req, res) => {
|
|
167
|
+
const ws = fileService.getWorkspace(req.params.id);
|
|
168
|
+
if (!ws) {
|
|
169
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const { srcPath, destPath } = req.body;
|
|
173
|
+
if (!srcPath || !destPath) {
|
|
174
|
+
res.status(400).json({ error: 'srcPath and destPath are required' });
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const ok = await fileService.copyPath(ws, srcPath, destPath);
|
|
178
|
+
if (!ok) {
|
|
179
|
+
res.status(500).json({ error: 'Failed to copy' });
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
res.json({ ok: true });
|
|
183
|
+
});
|
|
184
|
+
router.post('/import-url', async (req, res) => {
|
|
185
|
+
const ws = fileService.getWorkspace(req.params.id);
|
|
186
|
+
if (!ws) {
|
|
187
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const { url, targetDir } = req.body;
|
|
191
|
+
if (!url) {
|
|
192
|
+
res.status(400).json({ error: 'url is required' });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
const result = await fileService.importFromUrl(ws, url, targetDir || '');
|
|
196
|
+
if (!result) {
|
|
197
|
+
res.status(500).json({ error: 'Failed to import from URL' });
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
res.json({ ok: true, path: result });
|
|
201
|
+
});
|
|
202
|
+
router.post('/import-path', async (req, res) => {
|
|
203
|
+
const ws = fileService.getWorkspace(req.params.id);
|
|
204
|
+
if (!ws) {
|
|
205
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const { absPath, targetDir } = req.body;
|
|
209
|
+
if (!absPath) {
|
|
210
|
+
res.status(400).json({ error: 'absPath is required' });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const result = await fileService.importFromAbsPath(ws, absPath, targetDir || '');
|
|
214
|
+
if (!result) {
|
|
215
|
+
res.status(500).json({ error: 'Failed to import file' });
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
res.json({ ok: true, path: result });
|
|
219
|
+
});
|
|
220
|
+
router.post('/upload', async (req, res) => {
|
|
221
|
+
const ws = fileService.getWorkspace(req.params.id);
|
|
222
|
+
if (!ws) {
|
|
223
|
+
res.status(404).json({ error: 'Workspace not found' });
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const { targetDir, files } = req.body;
|
|
227
|
+
if (!Array.isArray(files) || files.length === 0) {
|
|
228
|
+
res.status(400).json({ error: 'files are required' });
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const results = [];
|
|
232
|
+
for (const f of files) {
|
|
233
|
+
if (!f.name || !f.content)
|
|
234
|
+
continue;
|
|
235
|
+
const buffer = Buffer.from(f.content, 'base64');
|
|
236
|
+
const relPath = targetDir ? `${targetDir}/${f.name}` : f.name;
|
|
237
|
+
const ok = await fileService.writeFileBinary(ws, relPath, buffer);
|
|
238
|
+
if (ok)
|
|
239
|
+
results.push(relPath);
|
|
240
|
+
}
|
|
241
|
+
res.json({ ok: true, paths: results });
|
|
242
|
+
});
|
|
147
243
|
export default router;
|
|
148
244
|
//# sourceMappingURL=file.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 } from '../adapters/git.js';
|
|
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';
|
|
3
3
|
const router = Router({ mergeParams: true });
|
|
4
4
|
router.get('/status', async (req, res) => {
|
|
5
5
|
try {
|
|
@@ -149,5 +149,126 @@ router.post('/remotes', async (req, res) => {
|
|
|
149
149
|
res.status(500).json({ error: err.message });
|
|
150
150
|
}
|
|
151
151
|
});
|
|
152
|
+
router.post('/checkout-detached', async (req, res) => {
|
|
153
|
+
try {
|
|
154
|
+
const { commitHash } = req.body;
|
|
155
|
+
if (!commitHash) {
|
|
156
|
+
res.status(400).json({ error: 'commitHash is required' });
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
await gitCheckoutDetached(req.params.id, commitHash);
|
|
160
|
+
res.json({ ok: true });
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
res.status(500).json({ error: err.message });
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
router.post('/cherry-pick', async (req, res) => {
|
|
167
|
+
try {
|
|
168
|
+
const { commitHash } = req.body;
|
|
169
|
+
if (!commitHash) {
|
|
170
|
+
res.status(400).json({ error: 'commitHash is required' });
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
await gitCherryPick(req.params.id, commitHash);
|
|
174
|
+
res.json({ ok: true });
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
res.status(500).json({ error: err.message });
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
router.post('/create-branch', async (req, res) => {
|
|
181
|
+
try {
|
|
182
|
+
const { name, startPoint } = req.body;
|
|
183
|
+
if (!name) {
|
|
184
|
+
res.status(400).json({ error: 'name is required' });
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
await gitCreateBranch(req.params.id, name, startPoint);
|
|
188
|
+
res.json({ ok: true });
|
|
189
|
+
}
|
|
190
|
+
catch (err) {
|
|
191
|
+
res.status(500).json({ error: err.message });
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
router.post('/delete-branch', async (req, res) => {
|
|
195
|
+
try {
|
|
196
|
+
const { name, force } = req.body;
|
|
197
|
+
if (!name) {
|
|
198
|
+
res.status(400).json({ error: 'name is required' });
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
await gitDeleteBranch(req.params.id, name, force);
|
|
202
|
+
res.json({ ok: true });
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
res.status(500).json({ error: err.message });
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
router.post('/create-tag', async (req, res) => {
|
|
209
|
+
try {
|
|
210
|
+
const { name, commitHash } = req.body;
|
|
211
|
+
if (!name) {
|
|
212
|
+
res.status(400).json({ error: 'name is required' });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
await gitCreateTag(req.params.id, name, commitHash);
|
|
216
|
+
res.json({ ok: true });
|
|
217
|
+
}
|
|
218
|
+
catch (err) {
|
|
219
|
+
res.status(500).json({ error: err.message });
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
router.get('/commit-diff', async (req, res) => {
|
|
223
|
+
try {
|
|
224
|
+
const hash = req.query.hash;
|
|
225
|
+
if (!hash) {
|
|
226
|
+
res.status(400).json({ error: 'hash is required' });
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const diffs = await gitCommitDiff(req.params.id, hash);
|
|
230
|
+
res.json(diffs);
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
res.status(500).json({ error: err.message });
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
router.get('/remote-url', async (req, res) => {
|
|
237
|
+
try {
|
|
238
|
+
const url = await gitGetRemoteUrl(req.params.id);
|
|
239
|
+
res.json({ url });
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
res.status(500).json({ error: err.message });
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
router.get('/merge-base', async (req, res) => {
|
|
246
|
+
try {
|
|
247
|
+
const hash = await gitMergeBase(req.params.id);
|
|
248
|
+
res.json({ hash });
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
res.status(500).json({ error: err.message });
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
router.get('/config', async (req, res) => {
|
|
255
|
+
try {
|
|
256
|
+
const config = await gitGetConfig('local', req.params.id);
|
|
257
|
+
res.json(config);
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
res.status(500).json({ error: err.message });
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
router.post('/config', async (req, res) => {
|
|
264
|
+
try {
|
|
265
|
+
const { name, email, proxy } = req.body;
|
|
266
|
+
await gitSetConfig('local', { name, email, proxy }, req.params.id);
|
|
267
|
+
res.json({ ok: true });
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
res.status(500).json({ error: err.message });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
152
273
|
export default router;
|
|
153
274
|
//# sourceMappingURL=git.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import * as store from '../storage/iframe-bookmarks-store.js';
|
|
3
|
+
const router = Router();
|
|
4
|
+
router.get('/', (_req, res) => {
|
|
5
|
+
res.json(store.listBookmarks());
|
|
6
|
+
});
|
|
7
|
+
router.post('/', (req, res) => {
|
|
8
|
+
const { title, url, size } = req.body;
|
|
9
|
+
if (!title || !url) {
|
|
10
|
+
res.status(400).json({ error: 'title and url are required' });
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
res.status(201).json(store.addBookmark({ title, url, size }));
|
|
14
|
+
});
|
|
15
|
+
router.put('/:id', (req, res) => {
|
|
16
|
+
const { title, url, size } = req.body;
|
|
17
|
+
const updated = store.updateBookmark(req.params.id, { title, url, size });
|
|
18
|
+
if (!updated) {
|
|
19
|
+
res.status(404).json({ error: 'bookmark not found' });
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
res.json(updated);
|
|
23
|
+
});
|
|
24
|
+
router.delete('/:id', (req, res) => {
|
|
25
|
+
const ok = store.removeBookmark(req.params.id);
|
|
26
|
+
if (!ok) {
|
|
27
|
+
res.status(404).json({ error: 'bookmark not found' });
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
res.json({ ok: true });
|
|
31
|
+
});
|
|
32
|
+
export default router;
|
|
33
|
+
//# sourceMappingURL=iframe-bookmarks.js.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import * as store from '../storage/speech-recognition-store.js';
|
|
3
|
+
import { createSpeechSession } from '../services/speech-recognition/index.js';
|
|
4
|
+
const router = Router();
|
|
5
|
+
// REST: CRUD for speech recognition configs
|
|
6
|
+
router.get('/', (_req, res) => {
|
|
7
|
+
res.json(store.listSpeechConfigs());
|
|
8
|
+
});
|
|
9
|
+
router.post('/', (req, res) => {
|
|
10
|
+
const { provider, label, credentials } = req.body;
|
|
11
|
+
if (!provider || !credentials) {
|
|
12
|
+
res.status(400).json({ error: 'provider and credentials are required' });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const item = store.createSpeechConfig({ provider, label: label || provider, credentials });
|
|
16
|
+
res.status(201).json(item);
|
|
17
|
+
});
|
|
18
|
+
router.put('/:id', (req, res) => {
|
|
19
|
+
const { label, credentials } = req.body;
|
|
20
|
+
const updated = store.updateSpeechConfig(req.params.id, { label, credentials });
|
|
21
|
+
if (!updated) {
|
|
22
|
+
res.status(404).json({ error: 'Config not found' });
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
res.json(updated);
|
|
26
|
+
});
|
|
27
|
+
router.delete('/:id', (req, res) => {
|
|
28
|
+
if (!store.deleteSpeechConfig(req.params.id)) {
|
|
29
|
+
res.status(404).json({ error: 'Config not found' });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
res.status(204).end();
|
|
33
|
+
});
|
|
34
|
+
// Export a handler for WebSocket upgrade (speech streaming)
|
|
35
|
+
export async function handleSpeechStream(clientWs, configId) {
|
|
36
|
+
const config = configId
|
|
37
|
+
? store.getSpeechConfig(configId)
|
|
38
|
+
: store.getDefaultSpeechConfig();
|
|
39
|
+
if (!config) {
|
|
40
|
+
clientWs.close(4004, 'No speech recognition config found');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const session = await createSpeechSession(config);
|
|
45
|
+
session.onResult((result) => {
|
|
46
|
+
if (clientWs.readyState === 1) {
|
|
47
|
+
clientWs.send(JSON.stringify(result));
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
session.onError((err) => {
|
|
51
|
+
if (clientWs.readyState === 1) {
|
|
52
|
+
clientWs.send(JSON.stringify({ error: err.message }));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
session.onClose(() => {
|
|
56
|
+
if (clientWs.readyState === 1) {
|
|
57
|
+
clientWs.close(1000, 'Session ended');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
clientWs.on('message', (data) => {
|
|
61
|
+
if (Buffer.isBuffer(data)) {
|
|
62
|
+
session.sendAudio(data);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
const msg = data.toString();
|
|
66
|
+
if (msg === '{"type":"end"}' || msg === '{"type":"end"}') {
|
|
67
|
+
session.end();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
clientWs.on('close', () => {
|
|
72
|
+
session.end();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
clientWs.close(1011, err.message || 'Failed to create speech session');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export default router;
|
|
80
|
+
//# sourceMappingURL=speech-recognition.js.map
|
package/dist/services/agent.js
CHANGED
|
@@ -9,6 +9,7 @@ import { listChannels, updateChannel } from './channel.js';
|
|
|
9
9
|
import { ensureDir, getDataDir } from '../storage/json-store.js';
|
|
10
10
|
import { extractUsageFromOutput } from '../storage/usage.js';
|
|
11
11
|
const DEFAULT_AGENT_ROLE = 'agent';
|
|
12
|
+
export const AGENT_GENERATOR_PRESET_ID = 'agent-generator';
|
|
12
13
|
const VALID_RUNTIME_KINDS = ['open-agent-sdk', 'claude-code', 'codex', 'langchain'];
|
|
13
14
|
const VALID_TOOL_NAMES = new Set(BUILT_IN_AGENT_TOOLS.map((tool) => tool.name));
|
|
14
15
|
const ANTHROPIC_BRIDGE_PROVIDERS = [
|
|
@@ -24,11 +25,15 @@ export function isValidRole(role) {
|
|
|
24
25
|
export function listTemplates() {
|
|
25
26
|
const root = getGlobalAgentTemplatesDir();
|
|
26
27
|
if (!existsSync(root))
|
|
27
|
-
return [];
|
|
28
|
-
|
|
28
|
+
return [getDefaultAgentGeneratorPreset()];
|
|
29
|
+
const templates = readdirSync(root, { withFileTypes: true })
|
|
29
30
|
.filter((entry) => entry.isDirectory())
|
|
30
31
|
.map((entry) => readAgentTemplate(entry.name))
|
|
31
32
|
.filter((template) => Boolean(template));
|
|
33
|
+
if (!templates.some((template) => template.id === AGENT_GENERATOR_PRESET_ID)) {
|
|
34
|
+
templates.unshift(getDefaultAgentGeneratorPreset());
|
|
35
|
+
}
|
|
36
|
+
return templates;
|
|
32
37
|
}
|
|
33
38
|
export async function testConnection(workspaceId, data) {
|
|
34
39
|
if (workspaceId) {
|
|
@@ -509,21 +514,57 @@ function ensureWorkspaceAgentCopy(preset, agentspaceDir) {
|
|
|
509
514
|
}
|
|
510
515
|
export function readAgentTemplate(agentId) {
|
|
511
516
|
const filePath = join(getGlobalAgentTemplateDir(agentId), 'agent.json');
|
|
512
|
-
if (!existsSync(filePath))
|
|
513
|
-
return null;
|
|
517
|
+
if (!existsSync(filePath)) {
|
|
518
|
+
return agentId === AGENT_GENERATOR_PRESET_ID ? getDefaultAgentGeneratorPreset() : null;
|
|
519
|
+
}
|
|
514
520
|
try {
|
|
515
521
|
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
516
522
|
}
|
|
517
523
|
catch {
|
|
518
|
-
return null;
|
|
524
|
+
return agentId === AGENT_GENERATOR_PRESET_ID ? getDefaultAgentGeneratorPreset() : null;
|
|
519
525
|
}
|
|
520
526
|
}
|
|
527
|
+
function getDefaultAgentGeneratorPreset() {
|
|
528
|
+
return {
|
|
529
|
+
id: AGENT_GENERATOR_PRESET_ID,
|
|
530
|
+
name: 'Agent Generator',
|
|
531
|
+
role: 'agent',
|
|
532
|
+
description: '根据提示词生成其他 Agent 的名称、描述和 Markdown 系统提示。',
|
|
533
|
+
runtimeKind: 'claude-code',
|
|
534
|
+
modelProvider: undefined,
|
|
535
|
+
modelId: '',
|
|
536
|
+
apiBase: '',
|
|
537
|
+
apiKey: '',
|
|
538
|
+
workingDir: '',
|
|
539
|
+
mcps: {},
|
|
540
|
+
skills: [],
|
|
541
|
+
tools: [],
|
|
542
|
+
systemPrompt: [
|
|
543
|
+
'# Role',
|
|
544
|
+
'You are an Agent Spaces agent designer.',
|
|
545
|
+
'',
|
|
546
|
+
'# Responsibilities',
|
|
547
|
+
'- Convert user requirements into production-ready Agent preset metadata.',
|
|
548
|
+
'- Return only valid JSON with name, description, and systemPrompt.',
|
|
549
|
+
'- Write the systemPrompt in clear Markdown with role, responsibilities, workflow, constraints, and output expectations.',
|
|
550
|
+
'',
|
|
551
|
+
'# Constraints',
|
|
552
|
+
'- Do not include Markdown code fences around JSON.',
|
|
553
|
+
'- Keep names concise and descriptions practical.',
|
|
554
|
+
].join('\n'),
|
|
555
|
+
temperature: 0.2,
|
|
556
|
+
maxTokens: 4096,
|
|
557
|
+
enabled: true,
|
|
558
|
+
};
|
|
559
|
+
}
|
|
521
560
|
function sanitizeMarkdownFilename(name) {
|
|
522
561
|
const raw = basename(name).replace(/\.md$/i, '');
|
|
523
562
|
const safe = raw.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '') || 'skill';
|
|
524
563
|
return `${safe}.md`;
|
|
525
564
|
}
|
|
526
565
|
export function deletePreset(workspaceId, presetId) {
|
|
566
|
+
if (presetId === AGENT_GENERATOR_PRESET_ID)
|
|
567
|
+
return false;
|
|
527
568
|
const ws = getWorkspace(workspaceId);
|
|
528
569
|
if (!ws)
|
|
529
570
|
return null;
|
|
@@ -611,6 +652,8 @@ export function updateGlobalPreset(presetId, data) {
|
|
|
611
652
|
return updated;
|
|
612
653
|
}
|
|
613
654
|
export function deleteGlobalPreset(presetId) {
|
|
655
|
+
if (presetId === AGENT_GENERATOR_PRESET_ID)
|
|
656
|
+
return false;
|
|
614
657
|
const templateDir = getGlobalAgentTemplateDir(presetId);
|
|
615
658
|
if (!existsSync(templateDir))
|
|
616
659
|
return false;
|