lua-cli 3.7.2 → 3.7.4
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/README.md +26 -0
- package/dist/api/chat.api.service.d.ts.map +1 -1
- package/dist/api/chat.api.service.js +4 -0
- package/dist/api/chat.api.service.js.map +1 -1
- package/dist/api/http.client.d.ts +25 -0
- package/dist/api/http.client.d.ts.map +1 -1
- package/dist/api/http.client.js +88 -5
- package/dist/api/http.client.js.map +1 -1
- package/dist/cli/command-definitions.d.ts.map +1 -1
- package/dist/cli/command-definitions.js +1 -6
- package/dist/cli/command-definitions.js.map +1 -1
- package/dist/commands/chat.js +1 -1
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/index.d.ts +0 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +0 -1
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/test.js +1 -1
- package/dist/commands/test.js.map +1 -1
- package/dist/config/constants.d.ts +7 -0
- package/dist/config/constants.d.ts.map +1 -1
- package/dist/config/constants.js +10 -0
- package/dist/config/constants.js.map +1 -1
- package/dist/services/analytics.d.ts +6 -0
- package/dist/services/analytics.d.ts.map +1 -1
- package/dist/services/analytics.js +19 -0
- package/dist/services/analytics.js.map +1 -1
- package/dist/services/auth.d.ts +11 -4
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +35 -6
- package/dist/services/auth.js.map +1 -1
- package/dist/utils/auth-flows.d.ts +4 -4
- package/dist/utils/auth-flows.d.ts.map +1 -1
- package/dist/utils/auth-flows.js +53 -37
- package/dist/utils/auth-flows.js.map +1 -1
- package/dist/utils/keytar-loader.d.ts.map +1 -1
- package/dist/utils/keytar-loader.js +8 -1
- package/dist/utils/keytar-loader.js.map +1 -1
- package/dist/utils/sandbox-storage.js +1 -1
- package/dist/utils/sandbox-storage.js.map +1 -1
- package/node_modules/@lua/shared-types/dist/index.d.mts +92 -0
- package/node_modules/@lua/shared-types/dist/index.d.ts +92 -0
- package/node_modules/@lua/shared-types/dist/index.js +104 -0
- package/node_modules/@lua/shared-types/dist/index.mjs +79 -0
- package/node_modules/@lua/shared-types/package.json +26 -0
- package/node_modules/@lua/shared-types/src/ai-generate.types.ts +79 -0
- package/node_modules/@lua/shared-types/src/ai-generate.utils.ts +19 -0
- package/node_modules/@lua/shared-types/src/channel.type.ts +21 -0
- package/node_modules/@lua/shared-types/src/index.ts +5 -0
- package/node_modules/@lua/shared-types/src/sandbox-contract.ts +42 -0
- package/node_modules/@lua/shared-types/src/unstructured-types.ts +58 -0
- package/node_modules/@lua/shared-types/tsconfig.json +12 -0
- package/node_modules/@lua/shared-types/tsup.config.ts +9 -0
- package/package.json +11 -18
- package/scripts/resolve-workspace-deps.cjs +61 -0
- package/dist/commands/dev.d.ts +0 -27
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js +0 -130
- package/dist/commands/dev.js.map +0 -1
- package/dist/config/dev.constants.d.ts +0 -56
- package/dist/config/dev.constants.d.ts.map +0 -1
- package/dist/config/dev.constants.js +0 -70
- package/dist/config/dev.constants.js.map +0 -1
- package/dist/utils/dev-api.d.ts +0 -6
- package/dist/utils/dev-api.d.ts.map +0 -1
- package/dist/utils/dev-api.js +0 -6
- package/dist/utils/dev-api.js.map +0 -1
- package/dist/utils/dev-server.d.ts +0 -27
- package/dist/utils/dev-server.d.ts.map +0 -1
- package/dist/utils/dev-server.js +0 -736
- package/dist/utils/dev-server.js.map +0 -1
- package/dist/utils/dev-watcher.d.ts +0 -31
- package/dist/utils/dev-watcher.d.ts.map +0 -1
- package/dist/utils/dev-watcher.js +0 -126
- package/dist/utils/dev-watcher.js.map +0 -1
- package/dist/web/app.css +0 -7401
- package/dist/web/app.js +0 -204
- package/dist/web/index.html +0 -33
package/dist/utils/dev-server.js
DELETED
|
@@ -1,736 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dev Server Utilities
|
|
3
|
-
* Handles HTTP server, WebSocket connections, and all HTTP endpoints for dev mode
|
|
4
|
-
*/
|
|
5
|
-
import fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import { fileURLToPath } from 'url';
|
|
8
|
-
import { createServer } from 'http';
|
|
9
|
-
import { WebSocketServer } from 'ws';
|
|
10
|
-
import { readYamlConfig } from './files.js';
|
|
11
|
-
import { skillHandler } from '../primitives/index.js';
|
|
12
|
-
import { executeTool, createBroadcastConsole, loadEnvironmentVariables } from './sandbox.js';
|
|
13
|
-
import { getSandboxSkillId } from './sandbox-storage.js';
|
|
14
|
-
import { sendChatMessage } from './dev-api.js';
|
|
15
|
-
import { CORS_HEADERS, HTTP_STATUS, DEV_DEFAULTS } from '../config/dev.constants.js';
|
|
16
|
-
import { BASE_URLS } from '../config/constants.js';
|
|
17
|
-
import ProductApi from '../api/products.api.service.js';
|
|
18
|
-
import BasketApi from '../api/basket.api.service.js';
|
|
19
|
-
import OrderApi from '../api/order.api.service.js';
|
|
20
|
-
import CustomDataApi from '../api/custom.data.api.service.js';
|
|
21
|
-
import { setAgentPersona } from '../compiler/index.js';
|
|
22
|
-
import { loadManifest, getPrimitivesByKind, loadArtifact, getAgentPersona } from './artifact-loader.js';
|
|
23
|
-
import { PrimitiveKind } from '../compiler/types.js';
|
|
24
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
25
|
-
const __dirname = path.dirname(__filename);
|
|
26
|
-
/**
|
|
27
|
-
* Creates and starts the dev web server with chat interface and tool testing.
|
|
28
|
-
*
|
|
29
|
-
* @param apiKey - User's API key
|
|
30
|
-
* @param agentId - Agent ID
|
|
31
|
-
* @param skillId - Skill ID
|
|
32
|
-
* @param sandboxId - Sandbox skill ID
|
|
33
|
-
* @param port - Port to run server on
|
|
34
|
-
* @param yamlConfig - YAML config with skills and processors
|
|
35
|
-
* @returns Server instance with WebSocket and broadcast function
|
|
36
|
-
*/
|
|
37
|
-
export function createChatServer(apiKey, agentId, skillId, sandboxId, port, yamlConfig) {
|
|
38
|
-
const server = createServer((req, res) => {
|
|
39
|
-
// Enable CORS
|
|
40
|
-
Object.entries(CORS_HEADERS).forEach(([key, value]) => {
|
|
41
|
-
res.setHeader(key, value);
|
|
42
|
-
});
|
|
43
|
-
if (req.method === 'OPTIONS') {
|
|
44
|
-
res.writeHead(HTTP_STATUS.OK);
|
|
45
|
-
res.end();
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
// Route handlers
|
|
49
|
-
if (req.method === 'POST' && req.url === '/chat') {
|
|
50
|
-
handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, yamlConfig);
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
if (req.method === 'GET' && req.url === '/persona') {
|
|
54
|
-
handleGetPersonaEndpoint(req, res);
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
if (req.method === 'POST' && req.url === '/persona') {
|
|
58
|
-
handlePostPersonaEndpoint(req, res);
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
if (req.method === 'GET' && req.url === '/api/config') {
|
|
62
|
-
handleGetConfigEndpoint(req, res);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (req.method === 'GET' && req.url === '/api/skills') {
|
|
66
|
-
handleGetSkillsEndpoint(req, res);
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
if (req.method === 'GET' && req.url === '/env') {
|
|
70
|
-
handleGetEnvEndpoint(req, res);
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (req.method === 'POST' && req.url === '/env') {
|
|
74
|
-
handlePostEnvEndpoint(req, res);
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
if (req.method === 'GET' && req.url === '/tools') {
|
|
78
|
-
handleGetToolsEndpoint(req, res);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if (req.method === 'POST' && req.url === '/tools/test') {
|
|
82
|
-
handleToolTestEndpoint(req, res, apiKey, agentId, wss);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
// Products routes
|
|
86
|
-
if (req.url?.startsWith('/api/products')) {
|
|
87
|
-
handleProductsEndpoint(req, res, apiKey, agentId);
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
// Baskets routes
|
|
91
|
-
if (req.url?.startsWith('/api/baskets')) {
|
|
92
|
-
handleBasketsEndpoint(req, res, apiKey, agentId);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
// Orders routes
|
|
96
|
-
if (req.url?.startsWith('/api/orders')) {
|
|
97
|
-
handleOrdersEndpoint(req, res, apiKey, agentId);
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
// Custom Data routes
|
|
101
|
-
if (req.url?.startsWith('/api/custom-data')) {
|
|
102
|
-
handleCustomDataEndpoint(req, res, apiKey, agentId);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
if (req.method === 'GET' && req.url === '/') {
|
|
106
|
-
handleIndexEndpoint(req, res, apiKey, agentId, skillId, sandboxId);
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (req.method === 'GET' && req.url === '/app.js') {
|
|
110
|
-
handleStaticFile(req, res, 'app.js', 'application/javascript');
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (req.method === 'GET' && req.url === '/app.css') {
|
|
114
|
-
handleStaticFile(req, res, 'app.css', 'text/css');
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (req.method === 'GET' && req.url === '/tools-page.css') {
|
|
118
|
-
handleStaticFile(req, res, 'tools-page.css', 'text/css');
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
res.writeHead(HTTP_STATUS.NOT_FOUND);
|
|
122
|
-
res.end('Not Found');
|
|
123
|
-
});
|
|
124
|
-
// Create WebSocket server for log streaming
|
|
125
|
-
const wss = new WebSocketServer({ server });
|
|
126
|
-
wss.on('connection', (ws) => {
|
|
127
|
-
ws.on('close', () => {
|
|
128
|
-
// Client disconnected
|
|
129
|
-
});
|
|
130
|
-
ws.on('error', (error) => {
|
|
131
|
-
console.error('WebSocket error:', error);
|
|
132
|
-
});
|
|
133
|
-
// Send initial connection message
|
|
134
|
-
ws.send(JSON.stringify({
|
|
135
|
-
type: 'log',
|
|
136
|
-
subType: 'info',
|
|
137
|
-
message: 'Connected to CLI dev server',
|
|
138
|
-
timestamp: new Date().toISOString()
|
|
139
|
-
}));
|
|
140
|
-
});
|
|
141
|
-
server.listen(port, () => {
|
|
142
|
-
// Server started
|
|
143
|
-
});
|
|
144
|
-
// Function to broadcast logs to all connected clients
|
|
145
|
-
const broadcastLog = (message, subType = 'info') => {
|
|
146
|
-
const logMessage = {
|
|
147
|
-
type: 'log',
|
|
148
|
-
subType,
|
|
149
|
-
message,
|
|
150
|
-
timestamp: new Date().toISOString(),
|
|
151
|
-
id: Date.now().toString()
|
|
152
|
-
};
|
|
153
|
-
wss.clients.forEach((client) => {
|
|
154
|
-
if (client.readyState === 1) { // WebSocket.OPEN
|
|
155
|
-
client.send(JSON.stringify(logMessage));
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
return { server, wss, broadcastLog };
|
|
160
|
-
}
|
|
161
|
-
// ============================================================================
|
|
162
|
-
// ENDPOINT HANDLERS
|
|
163
|
-
// ============================================================================
|
|
164
|
-
/**
|
|
165
|
-
* Handles POST /chat - Send chat messages
|
|
166
|
-
*/
|
|
167
|
-
function handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, yamlConfig) {
|
|
168
|
-
let body = '';
|
|
169
|
-
req.on('data', (chunk) => {
|
|
170
|
-
body += chunk.toString();
|
|
171
|
-
});
|
|
172
|
-
req.on('end', async () => {
|
|
173
|
-
try {
|
|
174
|
-
const { message, persona } = JSON.parse(body);
|
|
175
|
-
const response = await sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, yamlConfig);
|
|
176
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
177
|
-
res.end(JSON.stringify({
|
|
178
|
-
success: response !== null,
|
|
179
|
-
text: response || 'Error sending message',
|
|
180
|
-
error: response === null ? 'Failed to send message' : null
|
|
181
|
-
}));
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
185
|
-
res.end(JSON.stringify({ success: false, error: 'Invalid request' }));
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
/**
|
|
190
|
-
* Handles GET /persona - Get current persona
|
|
191
|
-
*/
|
|
192
|
-
function handleGetPersonaEndpoint(req, res) {
|
|
193
|
-
try {
|
|
194
|
-
const persona = getAgentPersona() ?? '';
|
|
195
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
196
|
-
res.end(JSON.stringify({
|
|
197
|
-
success: true,
|
|
198
|
-
persona: persona
|
|
199
|
-
}));
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
203
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to read persona' }));
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Handles POST /persona - Update persona
|
|
208
|
-
*/
|
|
209
|
-
function handlePostPersonaEndpoint(req, res) {
|
|
210
|
-
let body = '';
|
|
211
|
-
req.on('data', (chunk) => {
|
|
212
|
-
body += chunk.toString();
|
|
213
|
-
});
|
|
214
|
-
req.on('end', async () => {
|
|
215
|
-
try {
|
|
216
|
-
const { persona } = JSON.parse(body);
|
|
217
|
-
setAgentPersona(persona);
|
|
218
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
219
|
-
res.end(JSON.stringify({
|
|
220
|
-
success: true,
|
|
221
|
-
message: 'Persona updated successfully'
|
|
222
|
-
}));
|
|
223
|
-
}
|
|
224
|
-
catch (error) {
|
|
225
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
226
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to update persona' }));
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
/**
|
|
231
|
-
* Handles GET /api/config - Get agent configuration
|
|
232
|
-
*/
|
|
233
|
-
function handleGetConfigEndpoint(req, res) {
|
|
234
|
-
try {
|
|
235
|
-
const config = readYamlConfig();
|
|
236
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
237
|
-
res.end(JSON.stringify({
|
|
238
|
-
agent: {
|
|
239
|
-
agentId: config?.agent?.agentId || '',
|
|
240
|
-
orgId: config?.agent?.orgId || ''
|
|
241
|
-
}
|
|
242
|
-
}));
|
|
243
|
-
}
|
|
244
|
-
catch (error) {
|
|
245
|
-
console.error('Error reading config:', error);
|
|
246
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
247
|
-
res.end(JSON.stringify({ error: 'Failed to read configuration' }));
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Handles GET /api/skills - Get all skills information from manifest
|
|
252
|
-
*/
|
|
253
|
-
function handleGetSkillsEndpoint(req, res) {
|
|
254
|
-
(async () => {
|
|
255
|
-
try {
|
|
256
|
-
const skillsData = [];
|
|
257
|
-
const config = readYamlConfig();
|
|
258
|
-
const yamlSkills = skillHandler.getFromYaml(config);
|
|
259
|
-
// Try to read from manifest
|
|
260
|
-
try {
|
|
261
|
-
const manifest = loadManifest();
|
|
262
|
-
const skills = getPrimitivesByKind(manifest, PrimitiveKind.SKILL);
|
|
263
|
-
for (const skill of skills) {
|
|
264
|
-
const yamlSkill = yamlSkills.find((s) => s.name === skill.name);
|
|
265
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
266
|
-
skillsData.push({
|
|
267
|
-
name: skill.name || DEV_DEFAULTS.SKILL_NAME,
|
|
268
|
-
description: skill.description || DEV_DEFAULTS.DESCRIPTION,
|
|
269
|
-
context: skill.context || '',
|
|
270
|
-
version: yamlSkill?.version || DEV_DEFAULTS.VERSION,
|
|
271
|
-
skillId: yamlSkill?.skillId || '',
|
|
272
|
-
sandboxId: sandboxId || '',
|
|
273
|
-
tools: skill.tools || []
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
catch {
|
|
278
|
-
// Fallback: Read from YAML config only (not compiled yet)
|
|
279
|
-
const toolsDir = path.join(process.cwd(), 'src', 'tools');
|
|
280
|
-
let toolNames = [];
|
|
281
|
-
if (fs.existsSync(toolsDir)) {
|
|
282
|
-
const toolFiles = fs.readdirSync(toolsDir)
|
|
283
|
-
.filter((file) => file.endsWith('.ts'))
|
|
284
|
-
.map((file) => file.replace('.ts', ''));
|
|
285
|
-
toolNames = toolFiles;
|
|
286
|
-
}
|
|
287
|
-
for (const skill of yamlSkills) {
|
|
288
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
289
|
-
skillsData.push({
|
|
290
|
-
name: skill.name || DEV_DEFAULTS.SKILL_NAME,
|
|
291
|
-
description: DEV_DEFAULTS.NOT_COMPILED_DESCRIPTION,
|
|
292
|
-
context: DEV_DEFAULTS.NOT_COMPILED_CONTEXT,
|
|
293
|
-
version: skill.version || DEV_DEFAULTS.VERSION,
|
|
294
|
-
skillId: skill.skillId || '',
|
|
295
|
-
sandboxId: sandboxId || '',
|
|
296
|
-
tools: toolNames // All tools for now since not compiled
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
301
|
-
res.end(JSON.stringify({
|
|
302
|
-
success: true,
|
|
303
|
-
skills: skillsData
|
|
304
|
-
}));
|
|
305
|
-
}
|
|
306
|
-
catch (error) {
|
|
307
|
-
console.error('Error reading skills:', error);
|
|
308
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
309
|
-
res.end(JSON.stringify({
|
|
310
|
-
success: false,
|
|
311
|
-
error: 'Failed to read skills configuration'
|
|
312
|
-
}));
|
|
313
|
-
}
|
|
314
|
-
})();
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Handles GET /env - Get environment variables
|
|
318
|
-
*/
|
|
319
|
-
function handleGetEnvEndpoint(req, res) {
|
|
320
|
-
try {
|
|
321
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
322
|
-
let envContent = '';
|
|
323
|
-
if (fs.existsSync(envPath)) {
|
|
324
|
-
envContent = fs.readFileSync(envPath, 'utf8');
|
|
325
|
-
}
|
|
326
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
327
|
-
res.end(JSON.stringify({
|
|
328
|
-
success: true,
|
|
329
|
-
content: envContent
|
|
330
|
-
}));
|
|
331
|
-
}
|
|
332
|
-
catch (error) {
|
|
333
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
334
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to read .env file' }));
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Handles POST /env - Update environment variables
|
|
339
|
-
*/
|
|
340
|
-
function handlePostEnvEndpoint(req, res) {
|
|
341
|
-
let body = '';
|
|
342
|
-
req.on('data', (chunk) => {
|
|
343
|
-
body += chunk.toString();
|
|
344
|
-
});
|
|
345
|
-
req.on('end', async () => {
|
|
346
|
-
try {
|
|
347
|
-
const { content } = JSON.parse(body);
|
|
348
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
349
|
-
// Write the .env file
|
|
350
|
-
fs.writeFileSync(envPath, content || '', 'utf8');
|
|
351
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
352
|
-
res.end(JSON.stringify({
|
|
353
|
-
success: true,
|
|
354
|
-
message: 'Environment variables updated successfully'
|
|
355
|
-
}));
|
|
356
|
-
}
|
|
357
|
-
catch (error) {
|
|
358
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
359
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to update .env file' }));
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
/**
|
|
364
|
-
* Handles GET /tools - Get all tools from manifest
|
|
365
|
-
*/
|
|
366
|
-
function handleGetToolsEndpoint(req, res) {
|
|
367
|
-
try {
|
|
368
|
-
const manifest = loadManifest();
|
|
369
|
-
const toolPrimitives = getPrimitivesByKind(manifest, PrimitiveKind.TOOL);
|
|
370
|
-
// Convert to tools object format expected by the UI
|
|
371
|
-
const tools = {};
|
|
372
|
-
for (const tool of toolPrimitives) {
|
|
373
|
-
tools[tool.name] = {
|
|
374
|
-
name: tool.name,
|
|
375
|
-
description: tool.description,
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
379
|
-
res.end(JSON.stringify({
|
|
380
|
-
success: true,
|
|
381
|
-
tools: tools
|
|
382
|
-
}));
|
|
383
|
-
}
|
|
384
|
-
catch (error) {
|
|
385
|
-
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
386
|
-
res.end(JSON.stringify({ success: false, error: 'Manifest not found. Run lua compile first.' }));
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Handles POST /tools/test - Test a tool
|
|
391
|
-
*/
|
|
392
|
-
function handleToolTestEndpoint(req, res, apiKey, agentId, wss) {
|
|
393
|
-
let body = '';
|
|
394
|
-
req.on('data', (chunk) => {
|
|
395
|
-
body += chunk.toString();
|
|
396
|
-
});
|
|
397
|
-
req.on('end', async () => {
|
|
398
|
-
try {
|
|
399
|
-
const { toolName, inputs } = JSON.parse(body);
|
|
400
|
-
// Load tool from manifest
|
|
401
|
-
let manifest;
|
|
402
|
-
try {
|
|
403
|
-
manifest = loadManifest();
|
|
404
|
-
}
|
|
405
|
-
catch {
|
|
406
|
-
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
407
|
-
res.end(JSON.stringify({ success: false, error: 'Manifest not found. Run lua compile first.' }));
|
|
408
|
-
return;
|
|
409
|
-
}
|
|
410
|
-
const tools = getPrimitivesByKind(manifest, PrimitiveKind.TOOL);
|
|
411
|
-
const tool = tools.find(t => t.name === toolName);
|
|
412
|
-
if (!tool) {
|
|
413
|
-
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
414
|
-
res.end(JSON.stringify({ success: false, error: 'Tool not found' }));
|
|
415
|
-
return;
|
|
416
|
-
}
|
|
417
|
-
// Load environment variables from all sources (.env + yaml)
|
|
418
|
-
const envVars = loadEnvironmentVariables();
|
|
419
|
-
// Load tool code from artifact (already uncompressed)
|
|
420
|
-
const toolCode = loadArtifact(tool, process.cwd());
|
|
421
|
-
// Broadcast tool test start
|
|
422
|
-
wss.clients.forEach((client) => {
|
|
423
|
-
if (client.readyState === 1) {
|
|
424
|
-
client.send(JSON.stringify({
|
|
425
|
-
type: 'log',
|
|
426
|
-
subType: 'info',
|
|
427
|
-
message: `🧪 Testing tool: ${toolName}`,
|
|
428
|
-
timestamp: new Date().toISOString(),
|
|
429
|
-
id: Date.now().toString()
|
|
430
|
-
}));
|
|
431
|
-
}
|
|
432
|
-
});
|
|
433
|
-
// Create custom console that captures output and sends via WebSocket
|
|
434
|
-
const customConsole = createBroadcastConsole((logData) => {
|
|
435
|
-
wss.clients.forEach((client) => {
|
|
436
|
-
if (client.readyState === 1) { // WebSocket.OPEN
|
|
437
|
-
client.send(JSON.stringify(logData));
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
});
|
|
441
|
-
// Execute the tool using the common utility
|
|
442
|
-
const result = await executeTool({
|
|
443
|
-
toolCode,
|
|
444
|
-
inputs,
|
|
445
|
-
apiKey,
|
|
446
|
-
agentId,
|
|
447
|
-
channel: 'dev',
|
|
448
|
-
customConsole
|
|
449
|
-
});
|
|
450
|
-
// Broadcast tool test completion
|
|
451
|
-
wss.clients.forEach((client) => {
|
|
452
|
-
if (client.readyState === 1) {
|
|
453
|
-
client.send(JSON.stringify({
|
|
454
|
-
type: 'log',
|
|
455
|
-
subType: 'info',
|
|
456
|
-
message: `✅ Tool test completed: ${toolName}`,
|
|
457
|
-
timestamp: new Date().toISOString(),
|
|
458
|
-
id: (Date.now() + 1).toString()
|
|
459
|
-
}));
|
|
460
|
-
}
|
|
461
|
-
});
|
|
462
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
463
|
-
res.end(JSON.stringify({
|
|
464
|
-
success: true,
|
|
465
|
-
result: result
|
|
466
|
-
}));
|
|
467
|
-
}
|
|
468
|
-
catch (error) {
|
|
469
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
470
|
-
res.end(JSON.stringify({
|
|
471
|
-
success: false,
|
|
472
|
-
error: error.message || 'Tool execution failed'
|
|
473
|
-
}));
|
|
474
|
-
}
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
/**
|
|
478
|
-
* Handles GET / - Serve main HTML page
|
|
479
|
-
*/
|
|
480
|
-
function handleIndexEndpoint(req, res, apiKey, agentId, skillId, sandboxId) {
|
|
481
|
-
// Read the React app HTML template from dist directory
|
|
482
|
-
const htmlTemplate = fs.readFileSync(path.join(__dirname, '..', 'web', 'index.html'), 'utf8');
|
|
483
|
-
// Replace placeholders with actual values
|
|
484
|
-
const html = htmlTemplate
|
|
485
|
-
.replace('{{API_KEY}}', apiKey)
|
|
486
|
-
.replace('{{AGENT_ID}}', agentId)
|
|
487
|
-
.replace('{{SKILL_ID}}', skillId)
|
|
488
|
-
.replace('{{SANDBOX_ID}}', sandboxId);
|
|
489
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'text/html' });
|
|
490
|
-
res.end(html);
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Handles static file serving (JS, CSS)
|
|
494
|
-
*/
|
|
495
|
-
function handleStaticFile(req, res, filename, contentType) {
|
|
496
|
-
try {
|
|
497
|
-
const content = fs.readFileSync(path.join(__dirname, '..', 'web', filename), 'utf8');
|
|
498
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': contentType });
|
|
499
|
-
res.end(content);
|
|
500
|
-
}
|
|
501
|
-
catch (error) {
|
|
502
|
-
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'text/plain' });
|
|
503
|
-
res.end(`${filename} not found`);
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
/**
|
|
507
|
-
* Handler for products API using ProductApi service
|
|
508
|
-
*/
|
|
509
|
-
async function handleProductsEndpoint(req, res, apiKey, agentId) {
|
|
510
|
-
const productApi = new ProductApi(BASE_URLS.API, apiKey, agentId);
|
|
511
|
-
try {
|
|
512
|
-
let result;
|
|
513
|
-
if (req.method === 'GET') {
|
|
514
|
-
if (req.url.includes('/search')) {
|
|
515
|
-
const searchQuery = new URL(req.url, 'http://localhost').searchParams.get('searchQuery') || '';
|
|
516
|
-
result = await productApi.search(searchQuery);
|
|
517
|
-
}
|
|
518
|
-
else if (req.url.match(/\/api\/products\/[^/]+$/)) {
|
|
519
|
-
const productId = req.url.split('/').pop();
|
|
520
|
-
result = await productApi.getById(productId);
|
|
521
|
-
}
|
|
522
|
-
else {
|
|
523
|
-
const url = new URL(req.url, 'http://localhost');
|
|
524
|
-
const page = parseInt(url.searchParams.get('page') || '1');
|
|
525
|
-
const limit = parseInt(url.searchParams.get('limit') || '20');
|
|
526
|
-
result = await productApi.get(page, limit);
|
|
527
|
-
}
|
|
528
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
529
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
530
|
-
}
|
|
531
|
-
else if (req.method === 'POST') {
|
|
532
|
-
const body = await new Promise((resolve) => {
|
|
533
|
-
let data = '';
|
|
534
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
535
|
-
req.on('end', () => resolve(data));
|
|
536
|
-
});
|
|
537
|
-
const productData = JSON.parse(body);
|
|
538
|
-
result = await productApi.create(productData);
|
|
539
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
540
|
-
res.end(JSON.stringify({ success: true, data: { product: result } }));
|
|
541
|
-
}
|
|
542
|
-
else if (req.method === 'PUT') {
|
|
543
|
-
const body = await new Promise((resolve) => {
|
|
544
|
-
let data = '';
|
|
545
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
546
|
-
req.on('end', () => resolve(data));
|
|
547
|
-
});
|
|
548
|
-
const productData = JSON.parse(body);
|
|
549
|
-
result = await productApi.update(productData, productData.id);
|
|
550
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
551
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
552
|
-
}
|
|
553
|
-
else if (req.method === 'DELETE') {
|
|
554
|
-
const productId = req.url.split('/').pop();
|
|
555
|
-
result = await productApi.delete(productId);
|
|
556
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
557
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
catch (error) {
|
|
561
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
562
|
-
res.end(JSON.stringify({ success: false, error: error.message || 'API error' }));
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
/**
|
|
566
|
-
* Handler for baskets API using BasketApi service
|
|
567
|
-
*/
|
|
568
|
-
async function handleBasketsEndpoint(req, res, apiKey, agentId) {
|
|
569
|
-
const basketApi = new BasketApi(BASE_URLS.API, apiKey, agentId);
|
|
570
|
-
try {
|
|
571
|
-
let result;
|
|
572
|
-
if (req.method === 'GET') {
|
|
573
|
-
if (req.url.match(/\/api\/baskets\/[^/]+$/)) {
|
|
574
|
-
const basketId = req.url.split('/').pop();
|
|
575
|
-
result = await basketApi.getById(basketId);
|
|
576
|
-
}
|
|
577
|
-
else {
|
|
578
|
-
const url = new URL(req.url, 'http://localhost');
|
|
579
|
-
const statusParam = url.searchParams.get('status');
|
|
580
|
-
result = await basketApi.get(statusParam);
|
|
581
|
-
}
|
|
582
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
583
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
584
|
-
}
|
|
585
|
-
else if (req.method === 'POST') {
|
|
586
|
-
const body = await new Promise((resolve) => {
|
|
587
|
-
let data = '';
|
|
588
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
589
|
-
req.on('end', () => resolve(data));
|
|
590
|
-
});
|
|
591
|
-
const basketData = JSON.parse(body);
|
|
592
|
-
result = await basketApi.create(basketData);
|
|
593
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
594
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
595
|
-
}
|
|
596
|
-
else if (req.method === 'DELETE') {
|
|
597
|
-
const basketId = req.url.split('/').pop();
|
|
598
|
-
// Baskets don't have a direct delete in the API, use clear instead
|
|
599
|
-
result = await basketApi.clear(basketId);
|
|
600
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
601
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
catch (error) {
|
|
605
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
606
|
-
res.end(JSON.stringify({ success: false, error: error.message || 'API error' }));
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Handler for orders API using OrderApi service
|
|
611
|
-
*/
|
|
612
|
-
async function handleOrdersEndpoint(req, res, apiKey, agentId) {
|
|
613
|
-
const orderApi = new OrderApi(BASE_URLS.API, apiKey, agentId);
|
|
614
|
-
try {
|
|
615
|
-
let result;
|
|
616
|
-
if (req.method === 'GET') {
|
|
617
|
-
if (req.url.match(/\/api\/orders\/[^/]+$/)) {
|
|
618
|
-
const orderId = req.url.split('/').pop();
|
|
619
|
-
result = await orderApi.getById(orderId);
|
|
620
|
-
}
|
|
621
|
-
else {
|
|
622
|
-
const url = new URL(req.url, 'http://localhost');
|
|
623
|
-
const statusParam = url.searchParams.get('status');
|
|
624
|
-
result = await orderApi.get(statusParam);
|
|
625
|
-
}
|
|
626
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
627
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
628
|
-
}
|
|
629
|
-
else if (req.method === 'POST') {
|
|
630
|
-
const body = await new Promise((resolve) => {
|
|
631
|
-
let data = '';
|
|
632
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
633
|
-
req.on('end', () => resolve(data));
|
|
634
|
-
});
|
|
635
|
-
const orderData = JSON.parse(body);
|
|
636
|
-
result = await orderApi.create(orderData);
|
|
637
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
638
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
639
|
-
}
|
|
640
|
-
else if (req.method === 'PUT') {
|
|
641
|
-
if (req.url.includes('/status')) {
|
|
642
|
-
const orderId = req.url.split('/')[3];
|
|
643
|
-
const body = await new Promise((resolve) => {
|
|
644
|
-
let data = '';
|
|
645
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
646
|
-
req.on('end', () => resolve(data));
|
|
647
|
-
});
|
|
648
|
-
const { status } = JSON.parse(body);
|
|
649
|
-
result = await orderApi.updateStatus(status, orderId);
|
|
650
|
-
}
|
|
651
|
-
else {
|
|
652
|
-
const body = await new Promise((resolve) => {
|
|
653
|
-
let data = '';
|
|
654
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
655
|
-
req.on('end', () => resolve(data));
|
|
656
|
-
});
|
|
657
|
-
const orderData = JSON.parse(body);
|
|
658
|
-
const orderId = req.url.split('/').pop();
|
|
659
|
-
result = await orderApi.updateData(orderData, orderId);
|
|
660
|
-
}
|
|
661
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
662
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
catch (error) {
|
|
666
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
667
|
-
res.end(JSON.stringify({ success: false, error: error.message || 'API error' }));
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
/**
|
|
671
|
-
* Handler for custom data API using CustomDataApi service
|
|
672
|
-
*/
|
|
673
|
-
async function handleCustomDataEndpoint(req, res, apiKey, agentId) {
|
|
674
|
-
const customDataApi = new CustomDataApi(BASE_URLS.API, apiKey, agentId);
|
|
675
|
-
try {
|
|
676
|
-
let result;
|
|
677
|
-
const pathParts = req.url.split('/');
|
|
678
|
-
const collectionName = pathParts[3]; // /api/custom-data/{collection}
|
|
679
|
-
if (req.method === 'GET') {
|
|
680
|
-
if (req.url.includes('/search')) {
|
|
681
|
-
const url = new URL(req.url, 'http://localhost');
|
|
682
|
-
const searchText = url.searchParams.get('searchText') || '';
|
|
683
|
-
const limit = parseInt(url.searchParams.get('limit') || '10');
|
|
684
|
-
const scoreThreshold = parseFloat(url.searchParams.get('scoreThreshold') || '0.7');
|
|
685
|
-
result = await customDataApi.search(collectionName, searchText, limit, scoreThreshold);
|
|
686
|
-
}
|
|
687
|
-
else if (pathParts.length > 4) {
|
|
688
|
-
const entryId = pathParts[4];
|
|
689
|
-
result = await customDataApi.getEntry(collectionName, entryId);
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
const url = new URL(req.url, 'http://localhost');
|
|
693
|
-
const filter = url.searchParams.get('filter') ? JSON.parse(url.searchParams.get('filter')) : undefined;
|
|
694
|
-
const page = parseInt(url.searchParams.get('page') || '1');
|
|
695
|
-
const limit = parseInt(url.searchParams.get('limit') || '10');
|
|
696
|
-
result = await customDataApi.get(collectionName, filter, page, limit);
|
|
697
|
-
}
|
|
698
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
699
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
700
|
-
}
|
|
701
|
-
else if (req.method === 'POST') {
|
|
702
|
-
const body = await new Promise((resolve) => {
|
|
703
|
-
let data = '';
|
|
704
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
705
|
-
req.on('end', () => resolve(data));
|
|
706
|
-
});
|
|
707
|
-
const { data, searchText } = JSON.parse(body);
|
|
708
|
-
result = await customDataApi.create(collectionName, data, searchText);
|
|
709
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
710
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
711
|
-
}
|
|
712
|
-
else if (req.method === 'PUT') {
|
|
713
|
-
const entryId = pathParts[4];
|
|
714
|
-
const body = await new Promise((resolve) => {
|
|
715
|
-
let data = '';
|
|
716
|
-
req.on('data', (chunk) => { data += chunk; });
|
|
717
|
-
req.on('end', () => resolve(data));
|
|
718
|
-
});
|
|
719
|
-
const updateData = JSON.parse(body);
|
|
720
|
-
result = await customDataApi.update(collectionName, entryId, updateData.data, updateData.searchText);
|
|
721
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
722
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
723
|
-
}
|
|
724
|
-
else if (req.method === 'DELETE') {
|
|
725
|
-
const entryId = pathParts[4];
|
|
726
|
-
result = await customDataApi.delete(collectionName, entryId);
|
|
727
|
-
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
728
|
-
res.end(JSON.stringify({ success: true, data: result }));
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
catch (error) {
|
|
732
|
-
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
733
|
-
res.end(JSON.stringify({ success: false, error: error.message || 'API error' }));
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
//# sourceMappingURL=dev-server.js.map
|