lua-cli 2.2.8-alpha.2 โ 2.3.0-alpha.2
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/API_REFERENCE.md +1408 -0
- package/CLI_REFERENCE.md +818 -0
- package/GETTING_STARTED.md +1040 -0
- package/README.md +738 -424
- package/TEMPLATE_GUIDE.md +1398 -0
- package/dist/api/agent.api.service.d.ts +33 -6
- package/dist/api/agent.api.service.js +27 -0
- package/dist/api/auth.api.service.d.ts +31 -2
- package/dist/api/auth.api.service.js +29 -0
- package/dist/api/basket.api.service.d.ts +53 -11
- package/dist/api/basket.api.service.js +63 -14
- package/dist/api/chat.api.service.d.ts +15 -3
- package/dist/api/chat.api.service.js +12 -0
- package/dist/api/credentials.d.ts +24 -0
- package/dist/api/credentials.js +46 -0
- package/dist/api/custom.data.api.service.d.ts +45 -9
- package/dist/api/custom.data.api.service.js +43 -9
- package/dist/api/lazy-instances.d.ts +49 -0
- package/dist/api/lazy-instances.js +95 -0
- package/dist/api/order.api.service.d.ts +34 -4
- package/dist/api/order.api.service.js +41 -3
- package/dist/api/products.api.service.d.ts +39 -9
- package/dist/api/products.api.service.js +43 -5
- package/dist/api/skills.api.service.d.ts +49 -2
- package/dist/api/skills.api.service.js +47 -1
- package/dist/api/tool.api.service.d.ts +39 -1
- package/dist/api/tool.api.service.js +38 -0
- package/dist/api/user.data.api.service.d.ts +23 -1
- package/dist/api/user.data.api.service.js +22 -0
- package/dist/api-exports.d.ts +236 -5
- package/dist/api-exports.js +264 -81
- package/dist/cli/command-definitions.d.ts +30 -0
- package/dist/cli/command-definitions.js +71 -0
- package/dist/commands/agents.d.ts +20 -0
- package/dist/commands/agents.js +24 -2
- package/dist/commands/apiKey.d.ts +23 -0
- package/dist/commands/apiKey.js +23 -0
- package/dist/commands/compile.d.ts +24 -0
- package/dist/commands/compile.js +67 -759
- package/dist/commands/configure.d.ts +24 -0
- package/dist/commands/configure.js +31 -96
- package/dist/commands/deploy.d.ts +31 -19
- package/dist/commands/deploy.js +45 -74
- package/dist/commands/destroy.d.ts +27 -0
- package/dist/commands/destroy.js +27 -1
- package/dist/commands/dev.d.ts +25 -62
- package/dist/commands/dev.js +58 -878
- package/dist/commands/init.d.ts +27 -0
- package/dist/commands/init.js +98 -260
- package/dist/commands/push.d.ts +24 -21
- package/dist/commands/push.js +39 -92
- package/dist/commands/test.d.ts +26 -0
- package/dist/commands/test.js +41 -188
- package/dist/common/basket.instance.d.ts +54 -3
- package/dist/common/basket.instance.js +56 -3
- package/dist/common/data.entry.instance.d.ts +25 -2
- package/dist/common/data.entry.instance.js +24 -0
- package/dist/common/http.client.d.ts +51 -1
- package/dist/common/http.client.js +50 -0
- package/dist/common/order.instance.d.ts +22 -0
- package/dist/common/order.instance.js +31 -4
- package/dist/common/product.instance.d.ts +22 -1
- package/dist/common/product.instance.js +24 -6
- package/dist/common/product.pagination.instance.d.ts +22 -2
- package/dist/common/product.pagination.instance.js +22 -1
- package/dist/common/product.search.instance.d.ts +13 -3
- package/dist/common/product.search.instance.js +12 -1
- package/dist/common/user.instance.d.ts +27 -3
- package/dist/common/user.instance.js +28 -7
- package/dist/config/auth.constants.d.ts +11 -0
- package/dist/config/auth.constants.js +11 -0
- package/dist/config/compile.constants.d.ts +67 -0
- package/dist/config/compile.constants.js +99 -0
- package/dist/config/constants.d.ts +5 -0
- package/dist/config/constants.js +5 -0
- package/dist/config/dev.constants.d.ts +65 -0
- package/dist/config/dev.constants.js +79 -0
- package/dist/config/init.constants.d.ts +23 -0
- package/dist/config/init.constants.js +41 -0
- package/dist/index.d.ts +19 -3
- package/dist/index.js +28 -44
- package/dist/interfaces/admin.d.ts +56 -50
- package/dist/interfaces/admin.js +4 -0
- package/dist/interfaces/agent.d.ts +21 -0
- package/dist/interfaces/agent.js +4 -0
- package/dist/interfaces/baskets.d.ts +60 -0
- package/dist/interfaces/baskets.js +12 -0
- package/dist/interfaces/chat.d.ts +48 -4
- package/dist/interfaces/chat.js +4 -0
- package/dist/interfaces/common.d.ts +62 -0
- package/dist/interfaces/common.js +8 -0
- package/dist/interfaces/compile.d.ts +11 -0
- package/dist/interfaces/compile.js +4 -0
- package/dist/interfaces/custom.data.d.ts +49 -19
- package/dist/interfaces/custom.data.js +4 -0
- package/dist/interfaces/deploy.d.ts +29 -0
- package/dist/interfaces/deploy.js +4 -0
- package/dist/interfaces/dev.d.ts +53 -0
- package/dist/interfaces/dev.js +5 -0
- package/dist/interfaces/init.d.ts +60 -0
- package/dist/interfaces/init.js +4 -0
- package/dist/interfaces/orders.d.ts +37 -0
- package/dist/interfaces/orders.js +12 -0
- package/dist/interfaces/product.d.ts +38 -10
- package/dist/interfaces/product.js +4 -0
- package/dist/interfaces/push.d.ts +26 -0
- package/dist/interfaces/push.js +4 -0
- package/dist/interfaces/test.d.ts +36 -0
- package/dist/interfaces/test.js +4 -0
- package/dist/services/auth.d.ts +54 -99
- package/dist/services/auth.js +76 -12
- package/dist/types/api-contracts.d.ts +211 -0
- package/dist/types/api-contracts.js +8 -0
- package/dist/types/compile.types.d.ts +76 -0
- package/dist/types/compile.types.js +4 -0
- package/dist/types/index.d.ts +23 -121
- package/dist/types/index.js +25 -14
- package/dist/types/skill.d.ts +142 -0
- package/dist/{skill.js โ types/skill.js} +66 -17
- package/dist/types/tool-validation.d.ts +34 -0
- package/dist/types/tool-validation.js +42 -0
- package/dist/utils/auth-flows.d.ts +26 -0
- package/dist/utils/auth-flows.js +141 -0
- package/dist/utils/bundling.d.ts +36 -0
- package/dist/utils/bundling.js +137 -0
- package/dist/utils/compile.d.ts +37 -0
- package/dist/utils/compile.js +242 -0
- package/dist/utils/deploy-api.d.ts +26 -0
- package/dist/utils/deploy-api.js +53 -0
- package/dist/utils/deploy-helpers.d.ts +46 -0
- package/dist/utils/deploy-helpers.js +86 -0
- package/dist/utils/deployment.d.ts +25 -0
- package/dist/utils/deployment.js +161 -0
- package/dist/utils/dev-api.d.ts +61 -0
- package/dist/utils/dev-api.js +262 -0
- package/dist/utils/dev-helpers.d.ts +46 -0
- package/dist/utils/dev-helpers.js +83 -0
- package/dist/utils/dev-server.d.ts +24 -0
- package/dist/utils/dev-server.js +555 -0
- package/dist/utils/dev-watcher.d.ts +31 -0
- package/dist/utils/dev-watcher.js +110 -0
- package/dist/utils/files.js +0 -5
- package/dist/utils/init-agent.d.ts +34 -0
- package/dist/utils/init-agent.js +129 -0
- package/dist/utils/init-helpers.d.ts +41 -0
- package/dist/utils/init-helpers.js +73 -0
- package/dist/utils/init-prompts.d.ts +47 -0
- package/dist/utils/init-prompts.js +168 -0
- package/dist/utils/push-api.d.ts +15 -0
- package/dist/utils/push-api.js +48 -0
- package/dist/utils/push-helpers.d.ts +38 -0
- package/dist/utils/push-helpers.js +84 -0
- package/dist/utils/sandbox-storage.d.ts +27 -0
- package/dist/utils/sandbox-storage.js +71 -0
- package/dist/utils/sandbox.js +78 -114
- package/dist/utils/skill-management.d.ts +14 -0
- package/dist/utils/skill-management.js +148 -0
- package/dist/utils/test-helpers.d.ts +40 -0
- package/dist/utils/test-helpers.js +92 -0
- package/dist/utils/test-prompts.d.ts +23 -0
- package/dist/utils/test-prompts.js +186 -0
- package/dist/utils/tool-detection.d.ts +18 -0
- package/dist/utils/tool-detection.js +110 -0
- package/dist/web/app.css +941 -17
- package/dist/web/app.js +174 -22
- package/dist/web/index.html +7 -1
- package/package.json +13 -4
- package/template/QUICKSTART.md +299 -144
- package/template/README.md +928 -349
- package/template/TOOL_EXAMPLES.md +655 -0
- package/template/package-lock.json +5 -5
- package/template/package.json +1 -1
- package/template/src/index.ts +147 -207
- package/template/src/tools/BasketTool.ts +128 -0
- package/template/src/tools/CustomDataTool.ts +7 -13
- package/template/src/tools/OrderTool.ts +54 -0
- package/template/src/tools/PaymentTool.ts +1 -1
- package/template/src/tools/ProductsTool.ts +56 -118
- package/template/src/tools/UserDataTool.ts +4 -26
- package/dist/common/config.d.ts +0 -5
- package/dist/common/config.js +0 -5
- package/dist/custom-data-api.d.ts +0 -72
- package/dist/custom-data-api.js +0 -174
- package/dist/product-api.d.ts +0 -189
- package/dist/product-api.js +0 -141
- package/dist/services/api.d.ts +0 -549
- package/dist/services/api.js +0 -596
- package/dist/skill.d.ts +0 -50
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -2
- package/dist/user-data-api.d.ts +0 -39
- package/dist/user-data-api.js +0 -50
- package/template/API.md +0 -604
- package/template/DEVELOPER.md +0 -771
- package/template/lua.skill.yaml +0 -7
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev Helper Utilities
|
|
3
|
+
* Small helper functions for dev mode
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { DEV_DEFAULTS } from '../config/dev.constants.js';
|
|
8
|
+
/**
|
|
9
|
+
* Reads the version from config (handles both old and new formats).
|
|
10
|
+
*
|
|
11
|
+
* @param config - The skill configuration
|
|
12
|
+
* @returns The version string
|
|
13
|
+
*/
|
|
14
|
+
export function readConfigVersion(config) {
|
|
15
|
+
let version = config?.skill?.version; // Legacy format
|
|
16
|
+
if (!version && config?.skills && config.skills.length > 0) {
|
|
17
|
+
version = config.skills[0].version; // New format - use first skill's version
|
|
18
|
+
}
|
|
19
|
+
return version || DEV_DEFAULTS.VERSION;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Reads the deploy.json file from .lua directory.
|
|
23
|
+
*
|
|
24
|
+
* @returns Parsed deploy data or null if not found
|
|
25
|
+
*/
|
|
26
|
+
export function readDeployJson() {
|
|
27
|
+
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
28
|
+
if (!fs.existsSync(deployPath)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
const deployContent = fs.readFileSync(deployPath, 'utf8');
|
|
32
|
+
return JSON.parse(deployContent);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Extracts skill ID from config (handles both old and new formats).
|
|
36
|
+
* For multi-skill projects, returns the first skill's ID.
|
|
37
|
+
*
|
|
38
|
+
* @param config - The skill configuration
|
|
39
|
+
* @returns The skill ID or null if not found
|
|
40
|
+
*/
|
|
41
|
+
export function extractSkillId(config) {
|
|
42
|
+
let skillId = config?.skill?.skillId; // Legacy format
|
|
43
|
+
if (!skillId && config?.skills && config.skills.length > 0) {
|
|
44
|
+
skillId = config.skills[0].skillId; // New format - use first skill
|
|
45
|
+
}
|
|
46
|
+
return skillId || null;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Validates that the configuration has required fields.
|
|
50
|
+
*
|
|
51
|
+
* @param config - The skill configuration to validate
|
|
52
|
+
* @throws Error if configuration is invalid
|
|
53
|
+
*/
|
|
54
|
+
export function validateConfig(config) {
|
|
55
|
+
if (!config) {
|
|
56
|
+
throw new Error("โ No lua.skill.yaml found. Please run this command from a skill directory.");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Validates that deploy data has skills.
|
|
61
|
+
*
|
|
62
|
+
* @param deployData - The deploy data to validate
|
|
63
|
+
* @throws Error if deploy data is invalid
|
|
64
|
+
*/
|
|
65
|
+
export function validateDeployData(deployData) {
|
|
66
|
+
if (!deployData) {
|
|
67
|
+
throw new Error("โ No deploy.json found. Compilation may have failed.");
|
|
68
|
+
}
|
|
69
|
+
if (!deployData.skills || !Array.isArray(deployData.skills) || deployData.skills.length === 0) {
|
|
70
|
+
throw new Error("โ No skills found in deploy.json. Compilation may have failed.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validates that config has required agent information.
|
|
75
|
+
*
|
|
76
|
+
* @param config - The skill configuration
|
|
77
|
+
* @throws Error if agent info is missing
|
|
78
|
+
*/
|
|
79
|
+
export function validateAgentConfig(config) {
|
|
80
|
+
if (!config.agent?.agentId) {
|
|
81
|
+
throw new Error("โ Missing agentId in skill configuration");
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev Server Utilities
|
|
3
|
+
* Handles HTTP server, WebSocket connections, and all HTTP endpoints for dev mode
|
|
4
|
+
*/
|
|
5
|
+
import { WebSocketServer } from 'ws';
|
|
6
|
+
/**
|
|
7
|
+
* Server instance with WebSocket and broadcast capabilities
|
|
8
|
+
*/
|
|
9
|
+
export interface DevServer {
|
|
10
|
+
server: any;
|
|
11
|
+
wss: WebSocketServer;
|
|
12
|
+
broadcastLog: (message: string, subType?: 'info' | 'warn' | 'error' | 'debug') => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Creates and starts the dev web server with chat interface and tool testing.
|
|
16
|
+
*
|
|
17
|
+
* @param apiKey - User's API key
|
|
18
|
+
* @param agentId - Agent ID
|
|
19
|
+
* @param skillId - Skill ID
|
|
20
|
+
* @param sandboxId - Sandbox skill ID
|
|
21
|
+
* @param port - Port to run server on
|
|
22
|
+
* @returns Server instance with WebSocket and broadcast function
|
|
23
|
+
*/
|
|
24
|
+
export declare function createChatServer(apiKey: string, agentId: string, skillId: string, sandboxId: string, port: number): DevServer;
|
|
@@ -0,0 +1,555 @@
|
|
|
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 { readSkillConfig, updateSkillYamlPersona } from './files.js';
|
|
11
|
+
import { executeTool, createBroadcastConsole, loadEnvironmentVariables } from './sandbox.js';
|
|
12
|
+
import { getSandboxSkillId } from './sandbox-storage.js';
|
|
13
|
+
import { sendChatMessage } from './dev-api.js';
|
|
14
|
+
import { CORS_HEADERS, HTTP_STATUS, DEV_DEFAULTS } from '../config/dev.constants.js';
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
/**
|
|
18
|
+
* Reads the deploy.json file from .lua directory
|
|
19
|
+
*
|
|
20
|
+
* @returns Parsed deploy data or null if not found
|
|
21
|
+
*/
|
|
22
|
+
function readDeployJson() {
|
|
23
|
+
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
24
|
+
if (!fs.existsSync(deployPath)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const deployContent = fs.readFileSync(deployPath, 'utf8');
|
|
28
|
+
return JSON.parse(deployContent);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Creates and starts the dev web server with chat interface and tool testing.
|
|
32
|
+
*
|
|
33
|
+
* @param apiKey - User's API key
|
|
34
|
+
* @param agentId - Agent ID
|
|
35
|
+
* @param skillId - Skill ID
|
|
36
|
+
* @param sandboxId - Sandbox skill ID
|
|
37
|
+
* @param port - Port to run server on
|
|
38
|
+
* @returns Server instance with WebSocket and broadcast function
|
|
39
|
+
*/
|
|
40
|
+
export function createChatServer(apiKey, agentId, skillId, sandboxId, port) {
|
|
41
|
+
const deployData = readDeployJson();
|
|
42
|
+
const server = createServer((req, res) => {
|
|
43
|
+
// Enable CORS
|
|
44
|
+
Object.entries(CORS_HEADERS).forEach(([key, value]) => {
|
|
45
|
+
res.setHeader(key, value);
|
|
46
|
+
});
|
|
47
|
+
if (req.method === 'OPTIONS') {
|
|
48
|
+
res.writeHead(HTTP_STATUS.OK);
|
|
49
|
+
res.end();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Route handlers
|
|
53
|
+
if (req.method === 'POST' && req.url === '/chat') {
|
|
54
|
+
handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (req.method === 'GET' && req.url === '/persona') {
|
|
58
|
+
handleGetPersonaEndpoint(req, res);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (req.method === 'POST' && req.url === '/persona') {
|
|
62
|
+
handlePostPersonaEndpoint(req, res);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (req.method === 'GET' && req.url === '/api/config') {
|
|
66
|
+
handleGetConfigEndpoint(req, res);
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (req.method === 'GET' && req.url === '/api/skills') {
|
|
70
|
+
handleGetSkillsEndpoint(req, res);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (req.method === 'GET' && req.url === '/env') {
|
|
74
|
+
handleGetEnvEndpoint(req, res);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (req.method === 'POST' && req.url === '/env') {
|
|
78
|
+
handlePostEnvEndpoint(req, res);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (req.method === 'GET' && req.url === '/tools') {
|
|
82
|
+
handleGetToolsEndpoint(req, res);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (req.method === 'POST' && req.url === '/tools/test') {
|
|
86
|
+
handleToolTestEndpoint(req, res, apiKey, agentId, wss);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (req.method === 'GET' && req.url === '/') {
|
|
90
|
+
handleIndexEndpoint(req, res, apiKey, agentId, skillId, sandboxId);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (req.method === 'GET' && req.url === '/app.js') {
|
|
94
|
+
handleStaticFile(req, res, 'app.js', 'application/javascript');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (req.method === 'GET' && req.url === '/app.css') {
|
|
98
|
+
handleStaticFile(req, res, 'app.css', 'text/css');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (req.method === 'GET' && req.url === '/tools-page.css') {
|
|
102
|
+
handleStaticFile(req, res, 'tools-page.css', 'text/css');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
res.writeHead(HTTP_STATUS.NOT_FOUND);
|
|
106
|
+
res.end('Not Found');
|
|
107
|
+
});
|
|
108
|
+
// Create WebSocket server for log streaming
|
|
109
|
+
const wss = new WebSocketServer({ server });
|
|
110
|
+
wss.on('connection', (ws) => {
|
|
111
|
+
ws.on('close', () => {
|
|
112
|
+
// Client disconnected
|
|
113
|
+
});
|
|
114
|
+
ws.on('error', (error) => {
|
|
115
|
+
console.error('WebSocket error:', error);
|
|
116
|
+
});
|
|
117
|
+
// Send initial connection message
|
|
118
|
+
ws.send(JSON.stringify({
|
|
119
|
+
type: 'log',
|
|
120
|
+
subType: 'info',
|
|
121
|
+
message: 'Connected to CLI dev server',
|
|
122
|
+
timestamp: new Date().toISOString()
|
|
123
|
+
}));
|
|
124
|
+
});
|
|
125
|
+
server.listen(port, () => {
|
|
126
|
+
// Server started
|
|
127
|
+
});
|
|
128
|
+
// Function to broadcast logs to all connected clients
|
|
129
|
+
const broadcastLog = (message, subType = 'info') => {
|
|
130
|
+
const logMessage = {
|
|
131
|
+
type: 'log',
|
|
132
|
+
subType,
|
|
133
|
+
message,
|
|
134
|
+
timestamp: new Date().toISOString(),
|
|
135
|
+
id: Date.now().toString()
|
|
136
|
+
};
|
|
137
|
+
wss.clients.forEach((client) => {
|
|
138
|
+
if (client.readyState === 1) { // WebSocket.OPEN
|
|
139
|
+
client.send(JSON.stringify(logMessage));
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
return { server, wss, broadcastLog };
|
|
144
|
+
}
|
|
145
|
+
// ============================================================================
|
|
146
|
+
// ENDPOINT HANDLERS
|
|
147
|
+
// ============================================================================
|
|
148
|
+
/**
|
|
149
|
+
* Handles POST /chat - Send chat messages
|
|
150
|
+
*/
|
|
151
|
+
function handleChatEndpoint(req, res, apiKey, agentId, skillId, sandboxId, deployData) {
|
|
152
|
+
let body = '';
|
|
153
|
+
req.on('data', (chunk) => {
|
|
154
|
+
body += chunk.toString();
|
|
155
|
+
});
|
|
156
|
+
req.on('end', async () => {
|
|
157
|
+
try {
|
|
158
|
+
const { message, persona } = JSON.parse(body);
|
|
159
|
+
const response = await sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona, deployData);
|
|
160
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
161
|
+
res.end(JSON.stringify({
|
|
162
|
+
success: response !== null,
|
|
163
|
+
text: response || 'Error sending message',
|
|
164
|
+
error: response === null ? 'Failed to send message' : null
|
|
165
|
+
}));
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
169
|
+
res.end(JSON.stringify({ success: false, error: 'Invalid request' }));
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Handles GET /persona - Get current persona
|
|
175
|
+
*/
|
|
176
|
+
function handleGetPersonaEndpoint(req, res) {
|
|
177
|
+
try {
|
|
178
|
+
const config = readSkillConfig();
|
|
179
|
+
const persona = config?.agent?.persona || '';
|
|
180
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
181
|
+
res.end(JSON.stringify({
|
|
182
|
+
success: true,
|
|
183
|
+
persona: persona
|
|
184
|
+
}));
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
188
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to read persona' }));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Handles POST /persona - Update persona
|
|
193
|
+
*/
|
|
194
|
+
function handlePostPersonaEndpoint(req, res) {
|
|
195
|
+
let body = '';
|
|
196
|
+
req.on('data', (chunk) => {
|
|
197
|
+
body += chunk.toString();
|
|
198
|
+
});
|
|
199
|
+
req.on('end', async () => {
|
|
200
|
+
try {
|
|
201
|
+
const { persona } = JSON.parse(body);
|
|
202
|
+
updateSkillYamlPersona(persona);
|
|
203
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
204
|
+
res.end(JSON.stringify({
|
|
205
|
+
success: true,
|
|
206
|
+
message: 'Persona updated successfully'
|
|
207
|
+
}));
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
211
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to update persona' }));
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Handles GET /api/config - Get agent configuration
|
|
217
|
+
*/
|
|
218
|
+
function handleGetConfigEndpoint(req, res) {
|
|
219
|
+
try {
|
|
220
|
+
const config = readSkillConfig();
|
|
221
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
222
|
+
res.end(JSON.stringify({
|
|
223
|
+
agent: {
|
|
224
|
+
agentId: config?.agent?.agentId || '',
|
|
225
|
+
orgId: config?.agent?.orgId || ''
|
|
226
|
+
}
|
|
227
|
+
}));
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
console.error('Error reading config:', error);
|
|
231
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
232
|
+
res.end(JSON.stringify({ error: 'Failed to read configuration' }));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Handles GET /api/skills - Get all skills information
|
|
237
|
+
*/
|
|
238
|
+
function handleGetSkillsEndpoint(req, res) {
|
|
239
|
+
(async () => {
|
|
240
|
+
try {
|
|
241
|
+
const skillsData = [];
|
|
242
|
+
// First try to read from deploy.json in the .lua directory
|
|
243
|
+
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
244
|
+
if (fs.existsSync(deployPath)) {
|
|
245
|
+
// Read from compiled deploy.json
|
|
246
|
+
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
247
|
+
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
248
|
+
// New format with skills array
|
|
249
|
+
for (const skill of deployData.skills) {
|
|
250
|
+
const sandboxId = await getSandboxSkillId(skill.name);
|
|
251
|
+
skillsData.push({
|
|
252
|
+
name: skill.name || DEV_DEFAULTS.SKILL_NAME,
|
|
253
|
+
description: skill.description || DEV_DEFAULTS.DESCRIPTION,
|
|
254
|
+
context: skill.context || '',
|
|
255
|
+
version: skill.version || DEV_DEFAULTS.VERSION,
|
|
256
|
+
skillId: skill.skillId || '',
|
|
257
|
+
sandboxId: sandboxId || '',
|
|
258
|
+
tools: skill.tools ? skill.tools.map((tool) => tool.name) : []
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else {
|
|
263
|
+
// Legacy format fallback
|
|
264
|
+
const toolNames = Object.keys(deployData.tools || {});
|
|
265
|
+
const sandboxId = await getSandboxSkillId(); // Legacy uses no skill name
|
|
266
|
+
skillsData.push({
|
|
267
|
+
name: deployData.name || 'Current Skill',
|
|
268
|
+
description: deployData.description || DEV_DEFAULTS.DESCRIPTION,
|
|
269
|
+
context: deployData.context || '',
|
|
270
|
+
version: deployData.version || DEV_DEFAULTS.VERSION,
|
|
271
|
+
skillId: deployData.skillId || '',
|
|
272
|
+
sandboxId: sandboxId || '',
|
|
273
|
+
tools: toolNames
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
// Fallback: Read from YAML and scan tools directory
|
|
279
|
+
const config = readSkillConfig();
|
|
280
|
+
const toolsDir = path.join(process.cwd(), 'src', 'tools');
|
|
281
|
+
let toolNames = [];
|
|
282
|
+
if (fs.existsSync(toolsDir)) {
|
|
283
|
+
const toolFiles = fs.readdirSync(toolsDir)
|
|
284
|
+
.filter((file) => file.endsWith('.ts'))
|
|
285
|
+
.map((file) => file.replace('.ts', ''));
|
|
286
|
+
toolNames = toolFiles;
|
|
287
|
+
}
|
|
288
|
+
if (config?.skills && Array.isArray(config.skills)) {
|
|
289
|
+
// New format: multiple skills
|
|
290
|
+
for (const skill of config.skills) {
|
|
291
|
+
const sandboxId = await getSandboxSkillId(skill.name);
|
|
292
|
+
skillsData.push({
|
|
293
|
+
name: skill.name || DEV_DEFAULTS.SKILL_NAME,
|
|
294
|
+
description: DEV_DEFAULTS.NOT_COMPILED_DESCRIPTION,
|
|
295
|
+
context: DEV_DEFAULTS.NOT_COMPILED_CONTEXT,
|
|
296
|
+
version: skill.version || DEV_DEFAULTS.VERSION,
|
|
297
|
+
skillId: skill.skillId || '',
|
|
298
|
+
sandboxId: sandboxId || '',
|
|
299
|
+
tools: toolNames // All tools for now since not compiled
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
else if (config?.skill) {
|
|
304
|
+
// Legacy format: single skill
|
|
305
|
+
const sandboxId = await getSandboxSkillId(); // Legacy uses no skill name
|
|
306
|
+
skillsData.push({
|
|
307
|
+
name: config.skill.name || 'Current Skill',
|
|
308
|
+
description: DEV_DEFAULTS.NOT_COMPILED_DESCRIPTION,
|
|
309
|
+
context: DEV_DEFAULTS.NOT_COMPILED_CONTEXT,
|
|
310
|
+
version: config.skill.version || DEV_DEFAULTS.VERSION,
|
|
311
|
+
skillId: config.skill.skillId || '',
|
|
312
|
+
sandboxId: sandboxId || '',
|
|
313
|
+
tools: toolNames
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
318
|
+
res.end(JSON.stringify({
|
|
319
|
+
success: true,
|
|
320
|
+
skills: skillsData
|
|
321
|
+
}));
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
console.error('Error reading skills:', error);
|
|
325
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
326
|
+
res.end(JSON.stringify({
|
|
327
|
+
success: false,
|
|
328
|
+
error: 'Failed to read skills configuration'
|
|
329
|
+
}));
|
|
330
|
+
}
|
|
331
|
+
})();
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Handles GET /env - Get environment variables
|
|
335
|
+
*/
|
|
336
|
+
function handleGetEnvEndpoint(req, res) {
|
|
337
|
+
try {
|
|
338
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
339
|
+
let envContent = '';
|
|
340
|
+
if (fs.existsSync(envPath)) {
|
|
341
|
+
envContent = fs.readFileSync(envPath, 'utf8');
|
|
342
|
+
}
|
|
343
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
344
|
+
res.end(JSON.stringify({
|
|
345
|
+
success: true,
|
|
346
|
+
content: envContent
|
|
347
|
+
}));
|
|
348
|
+
}
|
|
349
|
+
catch (error) {
|
|
350
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
351
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to read .env file' }));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Handles POST /env - Update environment variables
|
|
356
|
+
*/
|
|
357
|
+
function handlePostEnvEndpoint(req, res) {
|
|
358
|
+
let body = '';
|
|
359
|
+
req.on('data', (chunk) => {
|
|
360
|
+
body += chunk.toString();
|
|
361
|
+
});
|
|
362
|
+
req.on('end', async () => {
|
|
363
|
+
try {
|
|
364
|
+
const { content } = JSON.parse(body);
|
|
365
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
366
|
+
// Write the .env file
|
|
367
|
+
fs.writeFileSync(envPath, content || '', 'utf8');
|
|
368
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
369
|
+
res.end(JSON.stringify({
|
|
370
|
+
success: true,
|
|
371
|
+
message: 'Environment variables updated successfully'
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
376
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to update .env file' }));
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* Handles GET /tools - Get all tools
|
|
382
|
+
*/
|
|
383
|
+
function handleGetToolsEndpoint(req, res) {
|
|
384
|
+
try {
|
|
385
|
+
// Read the deploy.json file to get tools
|
|
386
|
+
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
387
|
+
if (fs.existsSync(deployPath)) {
|
|
388
|
+
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
389
|
+
// Handle both new skills array format and legacy tools format
|
|
390
|
+
let tools = deployData.tools || {};
|
|
391
|
+
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
392
|
+
// New format: merge all tools from all skills
|
|
393
|
+
tools = {};
|
|
394
|
+
deployData.skills.forEach((skill) => {
|
|
395
|
+
if (skill.tools && Array.isArray(skill.tools)) {
|
|
396
|
+
skill.tools.forEach((tool) => {
|
|
397
|
+
tools[tool.name] = tool;
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
403
|
+
res.end(JSON.stringify({
|
|
404
|
+
success: true,
|
|
405
|
+
tools: tools
|
|
406
|
+
}));
|
|
407
|
+
}
|
|
408
|
+
else {
|
|
409
|
+
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
410
|
+
res.end(JSON.stringify({ success: false, error: 'deploy.json not found' }));
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
415
|
+
res.end(JSON.stringify({ success: false, error: 'Failed to load tools' }));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
/**
|
|
419
|
+
* Handles POST /tools/test - Test a tool
|
|
420
|
+
*/
|
|
421
|
+
function handleToolTestEndpoint(req, res, apiKey, agentId, wss) {
|
|
422
|
+
let body = '';
|
|
423
|
+
req.on('data', (chunk) => {
|
|
424
|
+
body += chunk.toString();
|
|
425
|
+
});
|
|
426
|
+
req.on('end', async () => {
|
|
427
|
+
try {
|
|
428
|
+
const { toolName, inputs } = JSON.parse(body);
|
|
429
|
+
// Read deploy.json to get the tool's execute function
|
|
430
|
+
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
431
|
+
if (!fs.existsSync(deployPath)) {
|
|
432
|
+
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
433
|
+
res.end(JSON.stringify({ success: false, error: 'deploy.json not found' }));
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
437
|
+
let tool = null;
|
|
438
|
+
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
439
|
+
// New format: search through skills array
|
|
440
|
+
for (const skill of deployData.skills) {
|
|
441
|
+
if (skill.tools && Array.isArray(skill.tools)) {
|
|
442
|
+
tool = skill.tools.find((t) => t.name === toolName);
|
|
443
|
+
if (tool)
|
|
444
|
+
break;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
// Legacy format: search in tools object
|
|
450
|
+
if (deployData.tools && deployData.tools[toolName]) {
|
|
451
|
+
tool = {
|
|
452
|
+
name: toolName,
|
|
453
|
+
...deployData.tools[toolName]
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (!tool) {
|
|
458
|
+
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'application/json' });
|
|
459
|
+
res.end(JSON.stringify({ success: false, error: 'Tool not found' }));
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
// Load environment variables from all sources (.env + yaml)
|
|
463
|
+
const envVars = loadEnvironmentVariables();
|
|
464
|
+
// Decompress and execute the tool
|
|
465
|
+
const { gunzipSync } = await import('zlib');
|
|
466
|
+
const { Buffer } = await import('buffer');
|
|
467
|
+
function decompressCode(compressedCode) {
|
|
468
|
+
const buffer = Buffer.from(compressedCode, 'base64');
|
|
469
|
+
return gunzipSync(buffer).toString('utf8');
|
|
470
|
+
}
|
|
471
|
+
const toolCode = decompressCode(tool.execute);
|
|
472
|
+
// Broadcast tool test start
|
|
473
|
+
wss.clients.forEach((client) => {
|
|
474
|
+
if (client.readyState === 1) {
|
|
475
|
+
client.send(JSON.stringify({
|
|
476
|
+
type: 'log',
|
|
477
|
+
subType: 'info',
|
|
478
|
+
message: `๐งช Testing tool: ${toolName}`,
|
|
479
|
+
timestamp: new Date().toISOString(),
|
|
480
|
+
id: Date.now().toString()
|
|
481
|
+
}));
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
// Create custom console that captures output and sends via WebSocket
|
|
485
|
+
const customConsole = createBroadcastConsole((logData) => {
|
|
486
|
+
wss.clients.forEach((client) => {
|
|
487
|
+
if (client.readyState === 1) { // WebSocket.OPEN
|
|
488
|
+
client.send(JSON.stringify(logData));
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
// Execute the tool using the common utility
|
|
493
|
+
const result = await executeTool({
|
|
494
|
+
toolCode,
|
|
495
|
+
inputs,
|
|
496
|
+
apiKey,
|
|
497
|
+
agentId,
|
|
498
|
+
customConsole
|
|
499
|
+
});
|
|
500
|
+
// Broadcast tool test completion
|
|
501
|
+
wss.clients.forEach((client) => {
|
|
502
|
+
if (client.readyState === 1) {
|
|
503
|
+
client.send(JSON.stringify({
|
|
504
|
+
type: 'log',
|
|
505
|
+
subType: 'info',
|
|
506
|
+
message: `โ
Tool test completed: ${toolName}`,
|
|
507
|
+
timestamp: new Date().toISOString(),
|
|
508
|
+
id: (Date.now() + 1).toString()
|
|
509
|
+
}));
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'application/json' });
|
|
513
|
+
res.end(JSON.stringify({
|
|
514
|
+
success: true,
|
|
515
|
+
result: result
|
|
516
|
+
}));
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
res.writeHead(HTTP_STATUS.SERVER_ERROR, { 'Content-Type': 'application/json' });
|
|
520
|
+
res.end(JSON.stringify({
|
|
521
|
+
success: false,
|
|
522
|
+
error: error.message || 'Tool execution failed'
|
|
523
|
+
}));
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Handles GET / - Serve main HTML page
|
|
529
|
+
*/
|
|
530
|
+
function handleIndexEndpoint(req, res, apiKey, agentId, skillId, sandboxId) {
|
|
531
|
+
// Read the React app HTML template from dist directory
|
|
532
|
+
const htmlTemplate = fs.readFileSync(path.join(__dirname, '..', 'web', 'index.html'), 'utf8');
|
|
533
|
+
// Replace placeholders with actual values
|
|
534
|
+
const html = htmlTemplate
|
|
535
|
+
.replace('{{API_KEY}}', apiKey)
|
|
536
|
+
.replace('{{AGENT_ID}}', agentId)
|
|
537
|
+
.replace('{{SKILL_ID}}', skillId)
|
|
538
|
+
.replace('{{SANDBOX_ID}}', sandboxId);
|
|
539
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': 'text/html' });
|
|
540
|
+
res.end(html);
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Handles static file serving (JS, CSS)
|
|
544
|
+
*/
|
|
545
|
+
function handleStaticFile(req, res, filename, contentType) {
|
|
546
|
+
try {
|
|
547
|
+
const content = fs.readFileSync(path.join(__dirname, '..', 'web', filename), 'utf8');
|
|
548
|
+
res.writeHead(HTTP_STATUS.OK, { 'Content-Type': contentType });
|
|
549
|
+
res.end(content);
|
|
550
|
+
}
|
|
551
|
+
catch (error) {
|
|
552
|
+
res.writeHead(HTTP_STATUS.NOT_FOUND, { 'Content-Type': 'text/plain' });
|
|
553
|
+
res.end(`${filename} not found`);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev File Watcher Utilities
|
|
3
|
+
* Handles file system watching and automatic recompilation
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Configuration for file watcher
|
|
7
|
+
*/
|
|
8
|
+
export interface FileWatcherConfig {
|
|
9
|
+
apiKey: string;
|
|
10
|
+
agentId: string;
|
|
11
|
+
readDeployJson: () => any | null;
|
|
12
|
+
broadcastLog: (message: string, subType?: 'info' | 'warn' | 'error' | 'debug') => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Checks if a file should be ignored during watching.
|
|
16
|
+
*
|
|
17
|
+
* @param filename - The filename to check
|
|
18
|
+
* @returns True if file should be ignored, false otherwise
|
|
19
|
+
*/
|
|
20
|
+
export declare function shouldIgnoreFile(filename: string | null): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Creates and starts a file watcher for development mode.
|
|
23
|
+
* Watches for file changes and automatically recompiles and pushes to sandbox.
|
|
24
|
+
*
|
|
25
|
+
* @param config - File watcher configuration
|
|
26
|
+
* @returns The watcher instance
|
|
27
|
+
*/
|
|
28
|
+
export declare function createFileWatcher(config: FileWatcherConfig): {
|
|
29
|
+
watcher: import("fs").FSWatcher;
|
|
30
|
+
cleanup: () => void;
|
|
31
|
+
};
|