agentstudio 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/.env +15 -0
  2. package/README.md +85 -0
  3. package/dist/bin/agentstudio.d.ts +3 -0
  4. package/dist/bin/agentstudio.d.ts.map +1 -0
  5. package/dist/bin/agentstudio.js +141 -0
  6. package/dist/bin/agentstudio.js.map +1 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +87 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/middleware/auth.d.ts +7 -0
  12. package/dist/middleware/auth.d.ts.map +1 -0
  13. package/dist/middleware/auth.js +21 -0
  14. package/dist/middleware/auth.js.map +1 -0
  15. package/dist/routes/agents.d.ts +4 -0
  16. package/dist/routes/agents.d.ts.map +1 -0
  17. package/dist/routes/agents.js +804 -0
  18. package/dist/routes/agents.js.map +1 -0
  19. package/dist/routes/auth.d.ts +4 -0
  20. package/dist/routes/auth.d.ts.map +1 -0
  21. package/dist/routes/auth.js +60 -0
  22. package/dist/routes/auth.js.map +1 -0
  23. package/dist/routes/files.d.ts +4 -0
  24. package/dist/routes/files.d.ts.map +1 -0
  25. package/dist/routes/files.js +301 -0
  26. package/dist/routes/files.js.map +1 -0
  27. package/dist/routes/mcp.d.ts +4 -0
  28. package/dist/routes/mcp.d.ts.map +1 -0
  29. package/dist/routes/mcp.js +652 -0
  30. package/dist/routes/mcp.js.map +1 -0
  31. package/dist/routes/media.d.ts +5 -0
  32. package/dist/routes/media.d.ts.map +1 -0
  33. package/dist/routes/media.js +117 -0
  34. package/dist/routes/media.js.map +1 -0
  35. package/dist/routes/slides.d.ts +4 -0
  36. package/dist/routes/slides.d.ts.map +1 -0
  37. package/dist/routes/slides.js +146 -0
  38. package/dist/routes/slides.js.map +1 -0
  39. package/dist/services/claudeSession.d.ts +83 -0
  40. package/dist/services/claudeSession.d.ts.map +1 -0
  41. package/dist/services/claudeSession.js +255 -0
  42. package/dist/services/claudeSession.js.map +1 -0
  43. package/dist/services/messageQueue.d.ts +31 -0
  44. package/dist/services/messageQueue.d.ts.map +1 -0
  45. package/dist/services/messageQueue.js +67 -0
  46. package/dist/services/messageQueue.js.map +1 -0
  47. package/dist/services/sessionManager.d.ts +132 -0
  48. package/dist/services/sessionManager.d.ts.map +1 -0
  49. package/dist/services/sessionManager.js +439 -0
  50. package/dist/services/sessionManager.js.map +1 -0
  51. package/dist/types/claude-history.d.ts +48 -0
  52. package/dist/types/claude-history.d.ts.map +1 -0
  53. package/dist/types/claude-history.js +2 -0
  54. package/dist/types/claude-history.js.map +1 -0
  55. package/dist/types/claude-versions.d.ts +31 -0
  56. package/dist/types/claude-versions.d.ts.map +1 -0
  57. package/dist/types/claude-versions.js +2 -0
  58. package/dist/types/claude-versions.js.map +1 -0
  59. package/dist/types/commands.d.ts +32 -0
  60. package/dist/types/commands.d.ts.map +1 -0
  61. package/dist/types/commands.js +2 -0
  62. package/dist/types/commands.js.map +1 -0
  63. package/dist/types/index.d.ts +81 -0
  64. package/dist/types/index.d.ts.map +1 -0
  65. package/dist/types/index.js +150 -0
  66. package/dist/types/index.js.map +1 -0
  67. package/dist/types/subagents.d.ts +88 -0
  68. package/dist/types/subagents.d.ts.map +1 -0
  69. package/dist/types/subagents.js +2 -0
  70. package/dist/types/subagents.js.map +1 -0
  71. package/dist/utils/agentStorage.d.ts +19 -0
  72. package/dist/utils/agentStorage.d.ts.map +1 -0
  73. package/dist/utils/agentStorage.js +110 -0
  74. package/dist/utils/agentStorage.js.map +1 -0
  75. package/dist/utils/claudeVersionStorage.d.ts +33 -0
  76. package/dist/utils/claudeVersionStorage.d.ts.map +1 -0
  77. package/dist/utils/claudeVersionStorage.js +168 -0
  78. package/dist/utils/claudeVersionStorage.js.map +1 -0
  79. package/dist/utils/jwt.d.ts +15 -0
  80. package/dist/utils/jwt.d.ts.map +1 -0
  81. package/dist/utils/jwt.js +28 -0
  82. package/dist/utils/jwt.js.map +1 -0
  83. package/dist/utils/projectMetadataStorage.d.ts +21 -0
  84. package/dist/utils/projectMetadataStorage.d.ts.map +1 -0
  85. package/dist/utils/projectMetadataStorage.js +68 -0
  86. package/dist/utils/projectMetadataStorage.js.map +1 -0
  87. package/frontend/dist/index.html +86 -0
  88. package/package.json +66 -0
  89. package/src/bin/agentstudio.ts +161 -0
  90. package/src/index.ts +100 -0
  91. package/src/middleware/auth.ts +26 -0
  92. package/src/routes/agents.ts +885 -0
  93. package/src/routes/auth.ts +73 -0
  94. package/src/routes/commands.ts.bak +441 -0
  95. package/src/routes/files.ts +352 -0
  96. package/src/routes/mcp.ts +751 -0
  97. package/src/routes/media.ts +140 -0
  98. package/src/routes/projects.ts.bak +601 -0
  99. package/src/routes/sessions.ts.bak +809 -0
  100. package/src/routes/settings.ts.bak +718 -0
  101. package/src/routes/slides.ts +170 -0
  102. package/src/routes/subagents.ts.bak +364 -0
  103. package/src/services/claudeSession.ts +293 -0
  104. package/src/services/messageQueue.ts +71 -0
  105. package/src/services/sessionManager.ts +532 -0
  106. package/src/types/claude-history.ts +50 -0
  107. package/src/types/claude-versions.ts +33 -0
  108. package/src/types/commands.ts +35 -0
  109. package/src/types/index.ts +248 -0
  110. package/src/types/subagents.ts +106 -0
  111. package/src/utils/agentStorage.ts +126 -0
  112. package/src/utils/claudeVersionStorage.ts +199 -0
  113. package/src/utils/jwt.ts +36 -0
  114. package/src/utils/projectMetadataStorage.ts +86 -0
  115. package/tsconfig.json +26 -0
@@ -0,0 +1,170 @@
1
+ import express, { Router } from 'express';
2
+ import fs from 'fs-extra';
3
+ import { existsSync } from 'fs';
4
+ import { join, dirname, resolve, relative } from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { z } from 'zod';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+
11
+ const router: Router = express.Router();
12
+
13
+ // Get working directory (project root)
14
+ const getWorkingDir = () => {
15
+ return resolve(__dirname, '../../..');
16
+ };
17
+
18
+ // Validation schemas
19
+ const ReadFileSchema = z.object({
20
+ path: z.string()
21
+ });
22
+
23
+ const ReadFilesSchema = z.object({
24
+ paths: z.array(z.string())
25
+ });
26
+
27
+ const WriteFileSchema = z.object({
28
+ path: z.string(),
29
+ content: z.string()
30
+ });
31
+
32
+ // Helper function to resolve and validate file path
33
+ const resolveSafePath = (filePath: string): string => {
34
+ const workingDir = getWorkingDir();
35
+ const resolvedPath = resolve(workingDir, filePath);
36
+
37
+ // Ensure the path is within the working directory for security
38
+ const relativePath = relative(workingDir, resolvedPath);
39
+ if (relativePath.startsWith('..') || resolve(workingDir, relativePath) !== resolvedPath) {
40
+ throw new Error('Path is outside working directory');
41
+ }
42
+
43
+ return resolvedPath;
44
+ };
45
+
46
+ // GET /api/files/read - Read a single file
47
+ router.get('/read', async (req, res) => {
48
+ try {
49
+ const { path } = req.query;
50
+
51
+ if (!path || typeof path !== 'string') {
52
+ return res.status(400).json({ error: 'File path is required' });
53
+ }
54
+
55
+ const fullPath = resolveSafePath(path);
56
+
57
+ if (!existsSync(fullPath)) {
58
+ return res.status(404).json({ error: 'File not found' });
59
+ }
60
+
61
+ const content = await fs.readFile(fullPath, 'utf-8');
62
+
63
+ res.json({
64
+ path,
65
+ content,
66
+ exists: true
67
+ });
68
+ } catch (error) {
69
+ console.error('Error reading file:', error);
70
+ if (error instanceof Error && error.message === 'Path is outside working directory') {
71
+ return res.status(403).json({ error: 'Access denied' });
72
+ }
73
+ res.status(500).json({ error: 'Failed to read file' });
74
+ }
75
+ });
76
+
77
+ // POST /api/files/read-multiple - Read multiple files
78
+ router.post('/read-multiple', async (req, res) => {
79
+ try {
80
+ const validation = ReadFilesSchema.safeParse(req.body);
81
+ if (!validation.success) {
82
+ return res.status(400).json({ error: 'Invalid request body', details: validation.error });
83
+ }
84
+
85
+ const { paths } = validation.data;
86
+
87
+ const results = await Promise.allSettled(
88
+ paths.map(async (path) => {
89
+ try {
90
+ const fullPath = resolveSafePath(path);
91
+ const exists = existsSync(fullPath);
92
+
93
+ if (!exists) {
94
+ return {
95
+ path,
96
+ content: null,
97
+ exists: false,
98
+ error: 'File not found'
99
+ };
100
+ }
101
+
102
+ const content = await fs.readFile(fullPath, 'utf-8');
103
+ return {
104
+ path,
105
+ content,
106
+ exists: true
107
+ };
108
+ } catch (error) {
109
+ return {
110
+ path,
111
+ content: null,
112
+ exists: false,
113
+ error: error instanceof Error ? error.message : 'Unknown error'
114
+ };
115
+ }
116
+ })
117
+ );
118
+
119
+ const files = results.map((result, index) => {
120
+ if (result.status === 'fulfilled') {
121
+ return result.value;
122
+ } else {
123
+ return {
124
+ path: paths[index],
125
+ content: null,
126
+ exists: false,
127
+ error: result.reason
128
+ };
129
+ }
130
+ });
131
+
132
+ res.json({ files });
133
+ } catch (error) {
134
+ console.error('Error reading files:', error);
135
+ res.status(500).json({ error: 'Failed to read files' });
136
+ }
137
+ });
138
+
139
+ // PUT /api/files/write - Write to a single file
140
+ router.put('/write', async (req, res) => {
141
+ try {
142
+ const validation = WriteFileSchema.safeParse(req.body);
143
+ if (!validation.success) {
144
+ return res.status(400).json({ error: 'Invalid request body', details: validation.error });
145
+ }
146
+
147
+ const { path, content } = validation.data;
148
+ const fullPath = resolveSafePath(path);
149
+
150
+ // Ensure directory exists
151
+ await fs.ensureDir(dirname(fullPath));
152
+
153
+ // Write the file
154
+ await fs.writeFile(fullPath, content, 'utf-8');
155
+
156
+ res.json({
157
+ success: true,
158
+ message: 'File written successfully',
159
+ path
160
+ });
161
+ } catch (error) {
162
+ console.error('Error writing file:', error);
163
+ if (error instanceof Error && error.message === 'Path is outside working directory') {
164
+ return res.status(403).json({ error: 'Access denied' });
165
+ }
166
+ res.status(500).json({ error: 'Failed to write file' });
167
+ }
168
+ });
169
+
170
+ export default router;
@@ -0,0 +1,364 @@
1
+ import express, { Router } from 'express';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ import { promisify } from 'util';
5
+ import matter from 'gray-matter';
6
+ import { Subagent, SubagentCreate, SubagentUpdate, SubagentFilter } from '../types/subagents.js';
7
+
8
+ const router: Router = express.Router();
9
+ const readdir = promisify(fs.readdir);
10
+ const readFile = promisify(fs.readFile);
11
+ const writeFile = promisify(fs.writeFile);
12
+ const mkdir = promisify(fs.mkdir);
13
+ const unlink = promisify(fs.unlink);
14
+ const stat = promisify(fs.stat);
15
+
16
+ // Get user subagents directory (~/.claude/agents)
17
+ const getUserSubagentsDir = () => path.join(process.env.HOME || process.env.USERPROFILE || '', '.claude', 'agents');
18
+
19
+ // Get project subagents directory (.claude/agents)
20
+ const getProjectSubagentsDir = (projectPath?: string) => {
21
+ if (projectPath) {
22
+ return path.join(projectPath, '.claude', 'agents');
23
+ }
24
+ return path.join(process.cwd(), '..', '.claude', 'agents');
25
+ };
26
+
27
+ // Ensure directory exists
28
+ async function ensureDir(dirPath: string) {
29
+ try {
30
+ await mkdir(dirPath, { recursive: true });
31
+ } catch (error) {
32
+ // Directory already exists
33
+ }
34
+ }
35
+
36
+ // Parse subagent file content
37
+ function parseSubagentContent(content: string): { frontmatter: any; body: string } {
38
+ try {
39
+ const parsed = matter(content);
40
+ return {
41
+ frontmatter: parsed.data,
42
+ body: parsed.content.trim()
43
+ };
44
+ } catch {
45
+ return {
46
+ frontmatter: {},
47
+ body: content
48
+ };
49
+ }
50
+ }
51
+
52
+ // Format subagent content with frontmatter
53
+ function formatSubagentContent(subagent: SubagentCreate | SubagentUpdate, existingContent?: string): string {
54
+ let frontmatter: any = {};
55
+
56
+ if (existingContent) {
57
+ const parsed = parseSubagentContent(existingContent);
58
+ frontmatter = parsed.frontmatter;
59
+ }
60
+
61
+ // Update frontmatter with new values
62
+ if ('name' in subagent && subagent.name) frontmatter.name = subagent.name;
63
+ if (subagent.description) frontmatter.description = subagent.description;
64
+ if (subagent.tools && subagent.tools.length > 0) {
65
+ frontmatter.tools = subagent.tools.join(', ');
66
+ }
67
+
68
+ // Build content
69
+ let content = '';
70
+ if (Object.keys(frontmatter).length > 0) {
71
+ content += '---\n';
72
+ for (const [key, value] of Object.entries(frontmatter)) {
73
+ content += `${key}: ${value}\n`;
74
+ }
75
+ content += '---\n\n';
76
+ }
77
+
78
+ if ('content' in subagent && subagent.content) {
79
+ content += subagent.content;
80
+ } else if (existingContent) {
81
+ const parsed = parseSubagentContent(existingContent);
82
+ content += parsed.body;
83
+ }
84
+
85
+ return content;
86
+ }
87
+
88
+ // Scan subagents in directory
89
+ async function scanSubagents(dirPath: string): Promise<Subagent[]> {
90
+ try {
91
+ await ensureDir(dirPath);
92
+ const subagents: Subagent[] = [];
93
+ const items = await readdir(dirPath, { withFileTypes: true });
94
+
95
+ for (const item of items) {
96
+ if (item.isFile() && item.name.endsWith('.md')) {
97
+ const subagentName = item.name.replace('.md', '');
98
+ const itemPath = path.join(dirPath, item.name);
99
+ const content = await readFile(itemPath, 'utf-8');
100
+ const parsed = parseSubagentContent(content);
101
+ const stats = await stat(itemPath);
102
+
103
+ subagents.push({
104
+ id: `user:${subagentName}`,
105
+ name: parsed.frontmatter.name || subagentName,
106
+ description: parsed.frontmatter.description || '',
107
+ content: parsed.body,
108
+ scope: 'user',
109
+ tools: parsed.frontmatter.tools ?
110
+ parsed.frontmatter.tools.split(',').map((s: string) => s.trim()) : undefined,
111
+ createdAt: stats.birthtime,
112
+ updatedAt: stats.mtime
113
+ });
114
+ }
115
+ }
116
+
117
+ return subagents;
118
+ } catch (error) {
119
+ console.error(`Error scanning subagents in ${dirPath}:`, error);
120
+ return [];
121
+ }
122
+ }
123
+
124
+ // GET /api/subagents - List all subagents
125
+ router.get('/', async (req, res) => {
126
+ try {
127
+ const filter: SubagentFilter = {
128
+ search: req.query.search as string
129
+ };
130
+ const projectPath = req.query.projectPath as string;
131
+
132
+ let subagents;
133
+ if (projectPath) {
134
+ // Get project-specific subagents
135
+ subagents = await scanSubagents(getProjectSubagentsDir(projectPath));
136
+ } else {
137
+ // Get user subagents
138
+ subagents = await scanSubagents(getUserSubagentsDir());
139
+ }
140
+
141
+ // Apply search filter
142
+ if (filter.search) {
143
+ const searchLower = filter.search.toLowerCase();
144
+ subagents = subagents.filter(subagent =>
145
+ subagent.name.toLowerCase().includes(searchLower) ||
146
+ subagent.description.toLowerCase().includes(searchLower) ||
147
+ subagent.content.toLowerCase().includes(searchLower)
148
+ );
149
+ }
150
+
151
+ // Sort by name
152
+ subagents.sort((a, b) => a.name.localeCompare(b.name));
153
+
154
+ res.json(subagents);
155
+ } catch (error) {
156
+ console.error('Error listing subagents:', error);
157
+ res.status(500).json({ error: 'Failed to list subagents' });
158
+ }
159
+ });
160
+
161
+ // GET /api/subagents/:id - Get specific subagent
162
+ router.get('/:id', async (req, res) => {
163
+ try {
164
+ const { id } = req.params;
165
+ const [scope, name] = id.split(':');
166
+
167
+ if (scope !== 'user') {
168
+ return res.status(400).json({ error: 'Invalid subagent scope' });
169
+ }
170
+
171
+ const dirPath = getUserSubagentsDir();
172
+ const filePath = path.join(dirPath, name + '.md');
173
+
174
+ try {
175
+ const content = await readFile(filePath, 'utf-8');
176
+ const parsed = parseSubagentContent(content);
177
+ const stats = await stat(filePath);
178
+
179
+ const subagent: Subagent = {
180
+ id,
181
+ name: parsed.frontmatter.name || name,
182
+ description: parsed.frontmatter.description || '',
183
+ content: parsed.body,
184
+ scope: 'user',
185
+ tools: parsed.frontmatter.tools ?
186
+ parsed.frontmatter.tools.split(',').map((s: string) => s.trim()) : undefined,
187
+ createdAt: stats.birthtime,
188
+ updatedAt: stats.mtime
189
+ };
190
+
191
+ res.json(subagent);
192
+ } catch (error) {
193
+ res.status(404).json({ error: 'Subagent not found' });
194
+ }
195
+ } catch (error) {
196
+ console.error('Error getting subagent:', error);
197
+ res.status(500).json({ error: 'Failed to get subagent' });
198
+ }
199
+ });
200
+
201
+ // POST /api/subagents - Create new subagent
202
+ router.post('/', async (req, res) => {
203
+ try {
204
+ const subagentData: SubagentCreate = req.body;
205
+
206
+ if (!subagentData.name || !subagentData.description || !subagentData.content) {
207
+ return res.status(400).json({ error: 'Missing required fields: name, description, content' });
208
+ }
209
+
210
+ if (!['user', 'project'].includes(subagentData.scope)) {
211
+ return res.status(400).json({ error: 'Invalid scope. Must be "user" or "project"' });
212
+ }
213
+
214
+ // Validate name format (lowercase letters and hyphens only)
215
+ const nameRegex = /^[a-z0-9-]+$/;
216
+ if (!nameRegex.test(subagentData.name)) {
217
+ return res.status(400).json({ error: 'Name must contain only lowercase letters, numbers, and hyphens' });
218
+ }
219
+
220
+ const projectPath = req.query.projectPath as string;
221
+ let dirPath: string;
222
+
223
+ if (subagentData.scope === 'project') {
224
+ if (!projectPath) {
225
+ return res.status(400).json({ error: 'Project path is required for project scope' });
226
+ }
227
+ dirPath = getProjectSubagentsDir(projectPath);
228
+ } else {
229
+ dirPath = getUserSubagentsDir();
230
+ }
231
+
232
+ const filePath = path.join(dirPath, subagentData.name + '.md');
233
+
234
+ // Check if subagent already exists
235
+ try {
236
+ await stat(filePath);
237
+ return res.status(409).json({ error: 'Subagent already exists' });
238
+ } catch {
239
+ // Subagent doesn't exist, continue
240
+ }
241
+
242
+ // Ensure directory exists
243
+ await ensureDir(dirPath);
244
+
245
+ // Format and write content
246
+ const content = formatSubagentContent(subagentData);
247
+ await writeFile(filePath, content, 'utf-8');
248
+
249
+ // Return created subagent
250
+ const stats = await stat(filePath);
251
+ const subagent: Subagent = {
252
+ id: `${subagentData.scope}:${subagentData.name}`,
253
+ name: subagentData.name,
254
+ description: subagentData.description,
255
+ content: subagentData.content,
256
+ scope: subagentData.scope,
257
+ tools: subagentData.tools,
258
+ createdAt: stats.birthtime,
259
+ updatedAt: stats.mtime
260
+ };
261
+
262
+ res.status(201).json(subagent);
263
+ } catch (error) {
264
+ console.error('Error creating subagent:', error);
265
+ res.status(500).json({ error: 'Failed to create subagent' });
266
+ }
267
+ });
268
+
269
+ // PUT /api/subagents/:id - Update subagent
270
+ router.put('/:id', async (req, res) => {
271
+ try {
272
+ const { id } = req.params;
273
+ const updateData: SubagentUpdate = req.body;
274
+ const [scope, name] = id.split(':');
275
+
276
+ if (!['user', 'project'].includes(scope)) {
277
+ return res.status(400).json({ error: 'Invalid subagent scope' });
278
+ }
279
+
280
+ const projectPath = req.query.projectPath as string;
281
+ let dirPath: string;
282
+
283
+ if (scope === 'project') {
284
+ if (!projectPath) {
285
+ return res.status(400).json({ error: 'Project path is required for project scope' });
286
+ }
287
+ dirPath = getProjectSubagentsDir(projectPath);
288
+ } else {
289
+ dirPath = getUserSubagentsDir();
290
+ }
291
+
292
+ const filePath = path.join(dirPath, name + '.md');
293
+
294
+ try {
295
+ // Read existing content
296
+ const existingContent = await readFile(filePath, 'utf-8');
297
+
298
+ // Format updated content
299
+ const content = formatSubagentContent(updateData, existingContent);
300
+ await writeFile(filePath, content, 'utf-8');
301
+
302
+ // Return updated subagent
303
+ const parsed = parseSubagentContent(content);
304
+ const stats = await stat(filePath);
305
+
306
+ const subagent: Subagent = {
307
+ id,
308
+ name: parsed.frontmatter.name || name,
309
+ description: parsed.frontmatter.description || '',
310
+ content: parsed.body,
311
+ scope: scope as 'user' | 'project',
312
+ tools: parsed.frontmatter.tools ?
313
+ parsed.frontmatter.tools.split(',').map((s: string) => s.trim()) : undefined,
314
+ createdAt: stats.birthtime,
315
+ updatedAt: stats.mtime
316
+ };
317
+
318
+ res.json(subagent);
319
+ } catch (error) {
320
+ res.status(404).json({ error: 'Subagent not found' });
321
+ }
322
+ } catch (error) {
323
+ console.error('Error updating subagent:', error);
324
+ res.status(500).json({ error: 'Failed to update subagent' });
325
+ }
326
+ });
327
+
328
+ // DELETE /api/subagents/:id - Delete subagent
329
+ router.delete('/:id', async (req, res) => {
330
+ try {
331
+ const { id } = req.params;
332
+ const [scope, name] = id.split(':');
333
+
334
+ if (!['user', 'project'].includes(scope)) {
335
+ return res.status(400).json({ error: 'Invalid subagent scope' });
336
+ }
337
+
338
+ const projectPath = req.query.projectPath as string;
339
+ let dirPath: string;
340
+
341
+ if (scope === 'project') {
342
+ if (!projectPath) {
343
+ return res.status(400).json({ error: 'Project path is required for project scope' });
344
+ }
345
+ dirPath = getProjectSubagentsDir(projectPath);
346
+ } else {
347
+ dirPath = getUserSubagentsDir();
348
+ }
349
+
350
+ const filePath = path.join(dirPath, name + '.md');
351
+
352
+ try {
353
+ await unlink(filePath);
354
+ res.status(204).send();
355
+ } catch (error) {
356
+ res.status(404).json({ error: 'Subagent not found' });
357
+ }
358
+ } catch (error) {
359
+ console.error('Error deleting subagent:', error);
360
+ res.status(500).json({ error: 'Failed to delete subagent' });
361
+ }
362
+ });
363
+
364
+ export default router;