@cloudcli-ai/cloudcli 1.29.4 → 1.30.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 (179) hide show
  1. package/README.de.md +1 -1
  2. package/README.ja.md +1 -1
  3. package/README.ko.md +1 -1
  4. package/README.md +1 -1
  5. package/README.ru.md +1 -1
  6. package/README.tr.md +252 -0
  7. package/README.zh-CN.md +1 -1
  8. package/dist/assets/index-DI22MZMb.css +32 -0
  9. package/dist/assets/index-RX-W_g_Q.js +1262 -0
  10. package/dist/index.html +2 -2
  11. package/dist-server/server/claude-sdk.js +13 -8
  12. package/dist-server/server/claude-sdk.js.map +1 -1
  13. package/dist-server/server/cursor-cli.js +7 -7
  14. package/dist-server/server/cursor-cli.js.map +1 -1
  15. package/dist-server/server/gemini-cli.js +5 -5
  16. package/dist-server/server/gemini-cli.js.map +1 -1
  17. package/dist-server/server/gemini-response-handler.js +2 -2
  18. package/dist-server/server/gemini-response-handler.js.map +1 -1
  19. package/dist-server/server/index.js +27 -25
  20. package/dist-server/server/index.js.map +1 -1
  21. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +103 -0
  22. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  23. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  24. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  25. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +266 -0
  26. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  27. package/dist-server/server/modules/providers/list/claude/claude.provider.js +13 -0
  28. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  29. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  30. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  31. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  32. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  33. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +282 -0
  34. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  35. package/dist-server/server/modules/providers/list/codex/codex.provider.js +13 -0
  36. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  37. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  38. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  39. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  40. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  41. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +369 -0
  42. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  43. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +13 -0
  44. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  45. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +131 -0
  46. package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -0
  47. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js +82 -0
  48. package/dist-server/server/modules/providers/list/gemini/gemini-mcp.provider.js.map +1 -0
  49. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js +207 -0
  50. package/dist-server/server/modules/providers/list/gemini/gemini-sessions.provider.js.map +1 -0
  51. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js +13 -0
  52. package/dist-server/server/modules/providers/list/gemini/gemini.provider.js.map +1 -0
  53. package/dist-server/server/modules/providers/provider.registry.js +31 -0
  54. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  55. package/dist-server/server/modules/providers/provider.routes.js +159 -0
  56. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  57. package/dist-server/server/modules/providers/services/mcp.service.js +69 -0
  58. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  59. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  60. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  61. package/dist-server/server/modules/providers/services/sessions.service.js +29 -0
  62. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  63. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +14 -0
  64. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  65. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  66. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  67. package/dist-server/server/modules/providers/tests/mcp.test.js +250 -0
  68. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  69. package/dist-server/server/openai-codex.js +5 -5
  70. package/dist-server/server/openai-codex.js.map +1 -1
  71. package/dist-server/server/routes/codex.js +2 -278
  72. package/dist-server/server/routes/codex.js.map +1 -1
  73. package/dist-server/server/routes/commands.js +0 -44
  74. package/dist-server/server/routes/commands.js.map +1 -1
  75. package/dist-server/server/routes/cursor.js +9 -489
  76. package/dist-server/server/routes/cursor.js.map +1 -1
  77. package/dist-server/server/routes/mcp-utils.js +1 -18
  78. package/dist-server/server/routes/mcp-utils.js.map +1 -1
  79. package/dist-server/server/routes/messages.js +6 -6
  80. package/dist-server/server/routes/messages.js.map +1 -1
  81. package/dist-server/server/routes/settings.js +10 -0
  82. package/dist-server/server/routes/settings.js.map +1 -1
  83. package/dist-server/server/routes/taskmaster.js +0 -459
  84. package/dist-server/server/routes/taskmaster.js.map +1 -1
  85. package/dist-server/server/shared/interfaces.js +2 -0
  86. package/dist-server/server/shared/interfaces.js.map +1 -0
  87. package/dist-server/server/shared/types.js +3 -0
  88. package/dist-server/server/shared/types.js.map +1 -0
  89. package/dist-server/server/shared/utils.js +150 -0
  90. package/dist-server/server/shared/utils.js.map +1 -0
  91. package/dist-server/server/utils/mcp-detector.js +0 -49
  92. package/dist-server/server/utils/mcp-detector.js.map +1 -1
  93. package/dist-server/shared/modelConstants.js +1 -0
  94. package/dist-server/shared/modelConstants.js.map +1 -1
  95. package/package.json +6 -3
  96. package/server/claude-sdk.js +14 -8
  97. package/server/cursor-cli.js +7 -7
  98. package/server/gemini-cli.js +5 -5
  99. package/server/gemini-response-handler.js +2 -2
  100. package/server/index.js +33 -29
  101. package/server/modules/providers/list/claude/claude-auth.provider.ts +123 -0
  102. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  103. package/server/modules/providers/list/claude/claude-sessions.provider.ts +306 -0
  104. package/server/modules/providers/list/claude/claude.provider.ts +15 -0
  105. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  106. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  107. package/server/modules/providers/list/codex/codex-sessions.provider.ts +319 -0
  108. package/server/modules/providers/list/codex/codex.provider.ts +15 -0
  109. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  110. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  111. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +421 -0
  112. package/server/modules/providers/list/cursor/cursor.provider.ts +15 -0
  113. package/server/modules/providers/list/gemini/gemini-auth.provider.ts +151 -0
  114. package/server/modules/providers/list/gemini/gemini-mcp.provider.ts +110 -0
  115. package/server/modules/providers/list/gemini/gemini-sessions.provider.ts +227 -0
  116. package/server/modules/providers/list/gemini/gemini.provider.ts +15 -0
  117. package/server/modules/providers/provider.registry.ts +36 -0
  118. package/server/modules/providers/provider.routes.ts +217 -0
  119. package/server/modules/providers/services/mcp.service.ts +94 -0
  120. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  121. package/server/modules/providers/services/sessions.service.ts +45 -0
  122. package/server/modules/providers/shared/base/abstract.provider.ts +20 -0
  123. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  124. package/server/modules/providers/tests/mcp.test.ts +293 -0
  125. package/server/openai-codex.js +5 -5
  126. package/server/routes/codex.js +2 -312
  127. package/server/routes/commands.js +0 -49
  128. package/server/routes/cursor.js +15 -527
  129. package/server/routes/mcp-utils.js +2 -19
  130. package/server/routes/messages.js +6 -6
  131. package/server/routes/settings.js +10 -0
  132. package/server/routes/taskmaster.js +0 -492
  133. package/server/shared/interfaces.ts +54 -0
  134. package/server/shared/types.ts +172 -0
  135. package/server/shared/utils.ts +193 -0
  136. package/server/tsconfig.json +6 -3
  137. package/server/utils/mcp-detector.js +0 -51
  138. package/shared/modelConstants.js +1 -0
  139. package/dist/assets/index-BBAE1OJ_.css +0 -32
  140. package/dist/assets/index-Cyya3LhN.js +0 -1262
  141. package/dist-server/server/providers/claude/adapter.js +0 -266
  142. package/dist-server/server/providers/claude/adapter.js.map +0 -1
  143. package/dist-server/server/providers/claude/status.js +0 -121
  144. package/dist-server/server/providers/claude/status.js.map +0 -1
  145. package/dist-server/server/providers/codex/adapter.js +0 -232
  146. package/dist-server/server/providers/codex/adapter.js.map +0 -1
  147. package/dist-server/server/providers/codex/status.js +0 -70
  148. package/dist-server/server/providers/codex/status.js.map +0 -1
  149. package/dist-server/server/providers/cursor/adapter.js +0 -342
  150. package/dist-server/server/providers/cursor/adapter.js.map +0 -1
  151. package/dist-server/server/providers/cursor/status.js +0 -118
  152. package/dist-server/server/providers/cursor/status.js.map +0 -1
  153. package/dist-server/server/providers/gemini/adapter.js +0 -174
  154. package/dist-server/server/providers/gemini/adapter.js.map +0 -1
  155. package/dist-server/server/providers/gemini/status.js +0 -104
  156. package/dist-server/server/providers/gemini/status.js.map +0 -1
  157. package/dist-server/server/providers/registry.js +0 -58
  158. package/dist-server/server/providers/registry.js.map +0 -1
  159. package/dist-server/server/providers/types.js +0 -117
  160. package/dist-server/server/providers/types.js.map +0 -1
  161. package/dist-server/server/providers/utils.js +0 -28
  162. package/dist-server/server/providers/utils.js.map +0 -1
  163. package/dist-server/server/routes/cli-auth.js +0 -25
  164. package/dist-server/server/routes/cli-auth.js.map +0 -1
  165. package/dist-server/server/routes/mcp.js +0 -480
  166. package/dist-server/server/routes/mcp.js.map +0 -1
  167. package/server/providers/claude/adapter.js +0 -278
  168. package/server/providers/claude/status.js +0 -136
  169. package/server/providers/codex/adapter.js +0 -248
  170. package/server/providers/codex/status.js +0 -78
  171. package/server/providers/cursor/adapter.js +0 -348
  172. package/server/providers/cursor/status.js +0 -128
  173. package/server/providers/gemini/adapter.js +0 -186
  174. package/server/providers/gemini/status.js +0 -111
  175. package/server/providers/registry.js +0 -67
  176. package/server/providers/types.js +0 -132
  177. package/server/providers/utils.js +0 -29
  178. package/server/routes/cli-auth.js +0 -27
  179. package/server/routes/mcp.js +0 -552
@@ -1,73 +1,9 @@
1
1
  import express from 'express';
2
- import { spawn } from 'child_process';
3
- import { promises as fs } from 'fs';
4
- import path from 'path';
5
- import os from 'os';
6
- import TOML from '@iarna/toml';
7
- import { getCodexSessions, deleteCodexSession } from '../projects.js';
8
- import { applyCustomSessionNames, sessionNamesDb } from '../database/db.js';
2
+ import { deleteCodexSession } from '../projects.js';
3
+ import { sessionNamesDb } from '../database/db.js';
9
4
 
10
5
  const router = express.Router();
11
6
 
12
- function createCliResponder(res) {
13
- let responded = false;
14
- return (status, payload) => {
15
- if (responded || res.headersSent) {
16
- return;
17
- }
18
- responded = true;
19
- res.status(status).json(payload);
20
- };
21
- }
22
-
23
- router.get('/config', async (req, res) => {
24
- try {
25
- const configPath = path.join(os.homedir(), '.codex', 'config.toml');
26
- const content = await fs.readFile(configPath, 'utf8');
27
- const config = TOML.parse(content);
28
-
29
- res.json({
30
- success: true,
31
- config: {
32
- model: config.model || null,
33
- mcpServers: config.mcp_servers || {},
34
- approvalMode: config.approval_mode || 'suggest'
35
- }
36
- });
37
- } catch (error) {
38
- if (error.code === 'ENOENT') {
39
- res.json({
40
- success: true,
41
- config: {
42
- model: null,
43
- mcpServers: {},
44
- approvalMode: 'suggest'
45
- }
46
- });
47
- } else {
48
- console.error('Error reading Codex config:', error);
49
- res.status(500).json({ success: false, error: error.message });
50
- }
51
- }
52
- });
53
-
54
- router.get('/sessions', async (req, res) => {
55
- try {
56
- const { projectPath } = req.query;
57
-
58
- if (!projectPath) {
59
- return res.status(400).json({ success: false, error: 'projectPath query parameter required' });
60
- }
61
-
62
- const sessions = await getCodexSessions(projectPath);
63
- applyCustomSessionNames(sessions, 'codex');
64
- res.json({ success: true, sessions });
65
- } catch (error) {
66
- console.error('Error fetching Codex sessions:', error);
67
- res.status(500).json({ success: false, error: error.message });
68
- }
69
- });
70
-
71
7
  router.delete('/sessions/:sessionId', async (req, res) => {
72
8
  try {
73
9
  const { sessionId } = req.params;
@@ -80,250 +16,4 @@ router.delete('/sessions/:sessionId', async (req, res) => {
80
16
  }
81
17
  });
82
18
 
83
- // MCP Server Management Routes
84
-
85
- router.get('/mcp/cli/list', async (req, res) => {
86
- try {
87
- const respond = createCliResponder(res);
88
- const proc = spawn('codex', ['mcp', 'list'], { stdio: ['pipe', 'pipe', 'pipe'] });
89
-
90
- let stdout = '';
91
- let stderr = '';
92
-
93
- proc.stdout?.on('data', (data) => { stdout += data.toString(); });
94
- proc.stderr?.on('data', (data) => { stderr += data.toString(); });
95
-
96
- proc.on('close', (code) => {
97
- if (code === 0) {
98
- respond(200, { success: true, output: stdout, servers: parseCodexListOutput(stdout) });
99
- } else {
100
- respond(500, { error: 'Codex CLI command failed', details: stderr || `Exited with code ${code}` });
101
- }
102
- });
103
-
104
- proc.on('error', (error) => {
105
- const isMissing = error?.code === 'ENOENT';
106
- respond(isMissing ? 503 : 500, {
107
- error: isMissing ? 'Codex CLI not installed' : 'Failed to run Codex CLI',
108
- details: error.message,
109
- code: error.code
110
- });
111
- });
112
- } catch (error) {
113
- res.status(500).json({ error: 'Failed to list MCP servers', details: error.message });
114
- }
115
- });
116
-
117
- router.post('/mcp/cli/add', async (req, res) => {
118
- try {
119
- const { name, command, args = [], env = {} } = req.body;
120
-
121
- if (!name || !command) {
122
- return res.status(400).json({ error: 'name and command are required' });
123
- }
124
-
125
- // Build: codex mcp add <name> [-e KEY=VAL]... -- <command> [args...]
126
- let cliArgs = ['mcp', 'add', name];
127
-
128
- Object.entries(env).forEach(([key, value]) => {
129
- cliArgs.push('-e', `${key}=${value}`);
130
- });
131
-
132
- cliArgs.push('--', command);
133
-
134
- if (args && args.length > 0) {
135
- cliArgs.push(...args);
136
- }
137
-
138
- const respond = createCliResponder(res);
139
- const proc = spawn('codex', cliArgs, { stdio: ['pipe', 'pipe', 'pipe'] });
140
-
141
- let stdout = '';
142
- let stderr = '';
143
-
144
- proc.stdout?.on('data', (data) => { stdout += data.toString(); });
145
- proc.stderr?.on('data', (data) => { stderr += data.toString(); });
146
-
147
- proc.on('close', (code) => {
148
- if (code === 0) {
149
- respond(200, { success: true, output: stdout, message: `MCP server "${name}" added successfully` });
150
- } else {
151
- respond(400, { error: 'Codex CLI command failed', details: stderr || `Exited with code ${code}` });
152
- }
153
- });
154
-
155
- proc.on('error', (error) => {
156
- const isMissing = error?.code === 'ENOENT';
157
- respond(isMissing ? 503 : 500, {
158
- error: isMissing ? 'Codex CLI not installed' : 'Failed to run Codex CLI',
159
- details: error.message,
160
- code: error.code
161
- });
162
- });
163
- } catch (error) {
164
- res.status(500).json({ error: 'Failed to add MCP server', details: error.message });
165
- }
166
- });
167
-
168
- router.delete('/mcp/cli/remove/:name', async (req, res) => {
169
- try {
170
- const { name } = req.params;
171
-
172
- const respond = createCliResponder(res);
173
- const proc = spawn('codex', ['mcp', 'remove', name], { stdio: ['pipe', 'pipe', 'pipe'] });
174
-
175
- let stdout = '';
176
- let stderr = '';
177
-
178
- proc.stdout?.on('data', (data) => { stdout += data.toString(); });
179
- proc.stderr?.on('data', (data) => { stderr += data.toString(); });
180
-
181
- proc.on('close', (code) => {
182
- if (code === 0) {
183
- respond(200, { success: true, output: stdout, message: `MCP server "${name}" removed successfully` });
184
- } else {
185
- respond(400, { error: 'Codex CLI command failed', details: stderr || `Exited with code ${code}` });
186
- }
187
- });
188
-
189
- proc.on('error', (error) => {
190
- const isMissing = error?.code === 'ENOENT';
191
- respond(isMissing ? 503 : 500, {
192
- error: isMissing ? 'Codex CLI not installed' : 'Failed to run Codex CLI',
193
- details: error.message,
194
- code: error.code
195
- });
196
- });
197
- } catch (error) {
198
- res.status(500).json({ error: 'Failed to remove MCP server', details: error.message });
199
- }
200
- });
201
-
202
- router.get('/mcp/cli/get/:name', async (req, res) => {
203
- try {
204
- const { name } = req.params;
205
-
206
- const respond = createCliResponder(res);
207
- const proc = spawn('codex', ['mcp', 'get', name], { stdio: ['pipe', 'pipe', 'pipe'] });
208
-
209
- let stdout = '';
210
- let stderr = '';
211
-
212
- proc.stdout?.on('data', (data) => { stdout += data.toString(); });
213
- proc.stderr?.on('data', (data) => { stderr += data.toString(); });
214
-
215
- proc.on('close', (code) => {
216
- if (code === 0) {
217
- respond(200, { success: true, output: stdout, server: parseCodexGetOutput(stdout) });
218
- } else {
219
- respond(404, { error: 'Codex CLI command failed', details: stderr || `Exited with code ${code}` });
220
- }
221
- });
222
-
223
- proc.on('error', (error) => {
224
- const isMissing = error?.code === 'ENOENT';
225
- respond(isMissing ? 503 : 500, {
226
- error: isMissing ? 'Codex CLI not installed' : 'Failed to run Codex CLI',
227
- details: error.message,
228
- code: error.code
229
- });
230
- });
231
- } catch (error) {
232
- res.status(500).json({ error: 'Failed to get MCP server details', details: error.message });
233
- }
234
- });
235
-
236
- router.get('/mcp/config/read', async (req, res) => {
237
- try {
238
- const configPath = path.join(os.homedir(), '.codex', 'config.toml');
239
-
240
- let configData = null;
241
-
242
- try {
243
- const fileContent = await fs.readFile(configPath, 'utf8');
244
- configData = TOML.parse(fileContent);
245
- } catch (error) {
246
- // Config file doesn't exist
247
- }
248
-
249
- if (!configData) {
250
- return res.json({ success: true, configPath, servers: [] }); }
251
-
252
- const servers = [];
253
-
254
- if (configData.mcp_servers && typeof configData.mcp_servers === 'object') {
255
- for (const [name, config] of Object.entries(configData.mcp_servers)) {
256
- servers.push({
257
- id: name,
258
- name: name,
259
- type: 'stdio',
260
- scope: 'user',
261
- config: {
262
- command: config.command || '',
263
- args: config.args || [],
264
- env: config.env || {}
265
- },
266
- raw: config
267
- });
268
- }
269
- }
270
-
271
- res.json({ success: true, configPath, servers });
272
- } catch (error) {
273
- res.status(500).json({ error: 'Failed to read Codex configuration', details: error.message });
274
- }
275
- });
276
-
277
- function parseCodexListOutput(output) {
278
- const servers = [];
279
- const lines = output.split('\n').filter(line => line.trim());
280
-
281
- for (const line of lines) {
282
- if (line.includes(':')) {
283
- const colonIndex = line.indexOf(':');
284
- const name = line.substring(0, colonIndex).trim();
285
-
286
- if (!name) continue;
287
-
288
- const rest = line.substring(colonIndex + 1).trim();
289
- let description = rest;
290
- let status = 'unknown';
291
-
292
- if (rest.includes('✓') || rest.includes('✗')) {
293
- const statusMatch = rest.match(/(.*?)\s*-\s*([✓✗].*)$/);
294
- if (statusMatch) {
295
- description = statusMatch[1].trim();
296
- status = statusMatch[2].includes('✓') ? 'connected' : 'failed';
297
- }
298
- }
299
-
300
- servers.push({ name, type: 'stdio', status, description });
301
- }
302
- }
303
-
304
- return servers;
305
- }
306
-
307
- function parseCodexGetOutput(output) {
308
- try {
309
- const jsonMatch = output.match(/\{[\s\S]*\}/);
310
- if (jsonMatch) {
311
- return JSON.parse(jsonMatch[0]);
312
- }
313
-
314
- const server = { raw_output: output };
315
- const lines = output.split('\n');
316
-
317
- for (const line of lines) {
318
- if (line.includes('Name:')) server.name = line.split(':')[1]?.trim();
319
- else if (line.includes('Type:')) server.type = line.split(':')[1]?.trim();
320
- else if (line.includes('Command:')) server.command = line.split(':')[1]?.trim();
321
- }
322
-
323
- return server;
324
- } catch (error) {
325
- return { raw_output: output, parse_error: error.message };
326
- }
327
- }
328
-
329
19
  export default router;
@@ -451,55 +451,6 @@ router.post('/list', async (req, res) => {
451
451
  }
452
452
  });
453
453
 
454
- /**
455
- * POST /api/commands/load
456
- * Load a specific command file and return its content and metadata
457
- */
458
- router.post('/load', async (req, res) => {
459
- try {
460
- const { commandPath } = req.body;
461
-
462
- if (!commandPath) {
463
- return res.status(400).json({
464
- error: 'Command path is required'
465
- });
466
- }
467
-
468
- // Security: Prevent path traversal
469
- const resolvedPath = path.resolve(commandPath);
470
- if (!resolvedPath.startsWith(path.resolve(os.homedir())) &&
471
- !resolvedPath.includes('.claude/commands')) {
472
- return res.status(403).json({
473
- error: 'Access denied',
474
- message: 'Command must be in .claude/commands directory'
475
- });
476
- }
477
-
478
- // Read and parse the command file
479
- const content = await fs.readFile(commandPath, 'utf8');
480
- const { data: metadata, content: commandContent } = parseFrontmatter(content);
481
-
482
- res.json({
483
- path: commandPath,
484
- metadata,
485
- content: commandContent
486
- });
487
- } catch (error) {
488
- if (error.code === 'ENOENT') {
489
- return res.status(404).json({
490
- error: 'Command not found',
491
- message: `Command file not found: ${req.body.commandPath}`
492
- });
493
- }
494
-
495
- console.error('Error loading command:', error);
496
- res.status(500).json({
497
- error: 'Failed to load command',
498
- message: error.message
499
- });
500
- }
501
- });
502
-
503
454
  /**
504
455
  * POST /api/commands/execute
505
456
  * Execute a command with argument replacement