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
package/dist/commands/dev.js
CHANGED
|
@@ -1,826 +1,75 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Dev Command
|
|
3
|
+
* Orchestrates the development mode with live reloading, chat interface, and tool testing
|
|
4
|
+
*/
|
|
5
|
+
import open from 'open';
|
|
4
6
|
import { compileCommand } from './compile.js';
|
|
5
7
|
import { checkApiKey, loadApiKey } from '../services/auth.js';
|
|
6
|
-
import {
|
|
7
|
-
import { executeTool, createBroadcastConsole, loadEnvironmentVariables } from '../utils/sandbox.js';
|
|
8
|
-
import { readSkillConfig, updateSkillYamlPersona } from '../utils/files.js';
|
|
8
|
+
import { readSkillConfig } from '../utils/files.js';
|
|
9
9
|
import { withErrorHandling, writeProgress, writeSuccess } from '../utils/cli.js';
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
catch (error) {
|
|
37
|
-
// Ignore storage errors
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
// Function to get all sandbox skill IDs for all skills
|
|
41
|
-
async function getAllSandboxSkillIds() {
|
|
42
|
-
const skillOverrides = [];
|
|
43
|
-
try {
|
|
44
|
-
// Read deploy.json to get all skills
|
|
45
|
-
const deployData = readDeployJson();
|
|
46
|
-
if (!deployData || !deployData.skills || !Array.isArray(deployData.skills)) {
|
|
47
|
-
return skillOverrides;
|
|
48
|
-
}
|
|
49
|
-
// For each skill, get its sandbox ID
|
|
50
|
-
for (const skill of deployData.skills) {
|
|
51
|
-
if (skill.skillId && skill.name) {
|
|
52
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
53
|
-
if (sandboxId) {
|
|
54
|
-
skillOverrides.push({
|
|
55
|
-
skillId: skill.skillId,
|
|
56
|
-
sandboxId: sandboxId
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
console.error('Error getting sandbox skill IDs:', error);
|
|
64
|
-
}
|
|
65
|
-
return skillOverrides;
|
|
66
|
-
}
|
|
67
|
-
// Function to send chat message to API
|
|
68
|
-
export async function sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona) {
|
|
69
|
-
try {
|
|
70
|
-
// Get all sandbox skill IDs for skill override
|
|
71
|
-
const allSkillOverrides = await getAllSandboxSkillIds();
|
|
72
|
-
// If no skills found, fallback to the provided skillId and sandboxId
|
|
73
|
-
const skillOverride = allSkillOverrides.length > 0 ? allSkillOverrides : [
|
|
74
|
-
{
|
|
75
|
-
skillId: skillId,
|
|
76
|
-
sandboxId: sandboxId
|
|
77
|
-
}
|
|
78
|
-
];
|
|
79
|
-
const chatRequest = {
|
|
80
|
-
messages: [
|
|
81
|
-
{
|
|
82
|
-
type: "text",
|
|
83
|
-
text: message
|
|
84
|
-
}
|
|
85
|
-
],
|
|
86
|
-
navigate: true,
|
|
87
|
-
skillOverride: skillOverride
|
|
88
|
-
};
|
|
89
|
-
// Add persona override if provided
|
|
90
|
-
if (persona) {
|
|
91
|
-
chatRequest.personaOverride = persona;
|
|
92
|
-
}
|
|
93
|
-
const response = await ApiService.Chat.sendMessage(agentId, chatRequest, apiKey);
|
|
94
|
-
if (!response.success) {
|
|
95
|
-
console.error(`❌ Chat API error: ${response.error?.message || 'Unknown error'}`);
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
return response.data?.text || null;
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
console.error("❌ Error sending chat message:", error);
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
// Function to create and start web server for chat interface
|
|
106
|
-
function createChatServer(apiKey, agentId, skillId, sandboxId, port = 3000) {
|
|
107
|
-
const server = createServer((req, res) => {
|
|
108
|
-
// Enable CORS
|
|
109
|
-
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
110
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
111
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
112
|
-
if (req.method === 'OPTIONS') {
|
|
113
|
-
res.writeHead(200);
|
|
114
|
-
res.end();
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
if (req.method === 'POST' && req.url === '/chat') {
|
|
118
|
-
let body = '';
|
|
119
|
-
req.on('data', chunk => {
|
|
120
|
-
body += chunk.toString();
|
|
121
|
-
});
|
|
122
|
-
req.on('end', async () => {
|
|
123
|
-
try {
|
|
124
|
-
const { message, persona } = JSON.parse(body);
|
|
125
|
-
const response = await sendChatMessage(apiKey, agentId, skillId, sandboxId, message, persona);
|
|
126
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
127
|
-
res.end(JSON.stringify({
|
|
128
|
-
success: response !== null,
|
|
129
|
-
text: response || 'Error sending message',
|
|
130
|
-
error: response === null ? 'Failed to send message' : null
|
|
131
|
-
}));
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
135
|
-
res.end(JSON.stringify({ success: false, error: 'Invalid request' }));
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
// Persona management endpoints
|
|
141
|
-
if (req.method === 'GET' && req.url === '/persona') {
|
|
142
|
-
try {
|
|
143
|
-
const config = readSkillConfig();
|
|
144
|
-
const persona = config?.agent?.persona || '';
|
|
145
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
146
|
-
res.end(JSON.stringify({
|
|
147
|
-
success: true,
|
|
148
|
-
persona: persona
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
catch (error) {
|
|
152
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
153
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to read persona' }));
|
|
154
|
-
}
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (req.method === 'GET' && req.url === '/api/config') {
|
|
158
|
-
try {
|
|
159
|
-
const config = readSkillConfig();
|
|
160
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
161
|
-
res.end(JSON.stringify({
|
|
162
|
-
agent: {
|
|
163
|
-
agentId: config?.agent?.agentId || '',
|
|
164
|
-
orgId: config?.agent?.orgId || ''
|
|
165
|
-
}
|
|
166
|
-
}));
|
|
167
|
-
}
|
|
168
|
-
catch (error) {
|
|
169
|
-
console.error('Error reading config:', error);
|
|
170
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
171
|
-
res.end(JSON.stringify({ error: 'Failed to read configuration' }));
|
|
172
|
-
}
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
if (req.method === 'GET' && req.url === '/api/skills') {
|
|
176
|
-
(async () => {
|
|
177
|
-
try {
|
|
178
|
-
const skillsData = [];
|
|
179
|
-
// First try to read from deploy.json in the .lua directory
|
|
180
|
-
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
181
|
-
if (fs.existsSync(deployPath)) {
|
|
182
|
-
// Read from compiled deploy.json
|
|
183
|
-
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
184
|
-
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
185
|
-
// New format with skills array
|
|
186
|
-
for (const skill of deployData.skills) {
|
|
187
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
188
|
-
skillsData.push({
|
|
189
|
-
name: skill.name || 'Unnamed Skill',
|
|
190
|
-
description: skill.description || 'A Lua skill for AI automation',
|
|
191
|
-
context: skill.context || '',
|
|
192
|
-
version: skill.version || '1.0.0',
|
|
193
|
-
skillId: skill.skillId || '',
|
|
194
|
-
sandboxId: sandboxId || '',
|
|
195
|
-
tools: skill.tools ? skill.tools.map((tool) => tool.name) : []
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
// Legacy format fallback
|
|
201
|
-
const toolNames = Object.keys(deployData.tools || {});
|
|
202
|
-
const sandboxId = await getSandboxSkillId(); // Legacy uses no skill name
|
|
203
|
-
skillsData.push({
|
|
204
|
-
name: deployData.name || 'Current Skill',
|
|
205
|
-
description: deployData.description || 'A Lua skill for AI automation',
|
|
206
|
-
context: deployData.context || '',
|
|
207
|
-
version: deployData.version || '1.0.0',
|
|
208
|
-
skillId: deployData.skillId || '',
|
|
209
|
-
sandboxId: sandboxId || '',
|
|
210
|
-
tools: toolNames
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
// Fallback: Read from YAML and scan tools directory
|
|
216
|
-
const config = readSkillConfig();
|
|
217
|
-
const toolsDir = path.join(process.cwd(), 'src', 'tools');
|
|
218
|
-
let toolNames = [];
|
|
219
|
-
if (fs.existsSync(toolsDir)) {
|
|
220
|
-
const toolFiles = fs.readdirSync(toolsDir)
|
|
221
|
-
.filter((file) => file.endsWith('.ts'))
|
|
222
|
-
.map((file) => file.replace('.ts', ''));
|
|
223
|
-
toolNames = toolFiles;
|
|
224
|
-
}
|
|
225
|
-
if (config?.skills && Array.isArray(config.skills)) {
|
|
226
|
-
// New format: multiple skills
|
|
227
|
-
for (const skill of config.skills) {
|
|
228
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
229
|
-
skillsData.push({
|
|
230
|
-
name: skill.name || 'Unnamed Skill',
|
|
231
|
-
description: 'A Lua skill for AI automation (not compiled)',
|
|
232
|
-
context: 'This skill has not been compiled yet. Run "lua compile" to see full context information.',
|
|
233
|
-
version: skill.version || '1.0.0',
|
|
234
|
-
skillId: skill.skillId || '',
|
|
235
|
-
sandboxId: sandboxId || '',
|
|
236
|
-
tools: toolNames // All tools for now since not compiled
|
|
237
|
-
});
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
else if (config?.skill) {
|
|
241
|
-
// Legacy format: single skill
|
|
242
|
-
const sandboxId = await getSandboxSkillId(); // Legacy uses no skill name
|
|
243
|
-
skillsData.push({
|
|
244
|
-
name: config.skill.name || 'Current Skill',
|
|
245
|
-
description: 'A Lua skill for AI automation (not compiled)',
|
|
246
|
-
context: 'This skill has not been compiled yet. Run "lua compile" to see full context information.',
|
|
247
|
-
version: config.skill.version || '1.0.0',
|
|
248
|
-
skillId: config.skill.skillId || '',
|
|
249
|
-
sandboxId: sandboxId || '',
|
|
250
|
-
tools: toolNames
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
255
|
-
res.end(JSON.stringify({
|
|
256
|
-
success: true,
|
|
257
|
-
skills: skillsData
|
|
258
|
-
}));
|
|
259
|
-
}
|
|
260
|
-
catch (error) {
|
|
261
|
-
console.error('Error reading skills:', error);
|
|
262
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
263
|
-
res.end(JSON.stringify({
|
|
264
|
-
success: false,
|
|
265
|
-
error: 'Failed to read skills configuration'
|
|
266
|
-
}));
|
|
267
|
-
}
|
|
268
|
-
})();
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
if (req.method === 'POST' && req.url === '/persona') {
|
|
272
|
-
let body = '';
|
|
273
|
-
req.on('data', chunk => {
|
|
274
|
-
body += chunk.toString();
|
|
275
|
-
});
|
|
276
|
-
req.on('end', async () => {
|
|
277
|
-
try {
|
|
278
|
-
const { persona } = JSON.parse(body);
|
|
279
|
-
// Update the YAML file
|
|
280
|
-
updateSkillYamlPersona(persona);
|
|
281
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
282
|
-
res.end(JSON.stringify({
|
|
283
|
-
success: true,
|
|
284
|
-
message: 'Persona updated successfully'
|
|
285
|
-
}));
|
|
286
|
-
}
|
|
287
|
-
catch (error) {
|
|
288
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
289
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to update persona' }));
|
|
290
|
-
}
|
|
291
|
-
});
|
|
292
|
-
return;
|
|
293
|
-
}
|
|
294
|
-
// Environment variables endpoints
|
|
295
|
-
if (req.method === 'GET' && req.url === '/env') {
|
|
296
|
-
try {
|
|
297
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
298
|
-
let envContent = '';
|
|
299
|
-
if (fs.existsSync(envPath)) {
|
|
300
|
-
envContent = fs.readFileSync(envPath, 'utf8');
|
|
301
|
-
}
|
|
302
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
303
|
-
res.end(JSON.stringify({
|
|
304
|
-
success: true,
|
|
305
|
-
content: envContent
|
|
306
|
-
}));
|
|
307
|
-
}
|
|
308
|
-
catch (error) {
|
|
309
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
310
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to read .env file' }));
|
|
311
|
-
}
|
|
312
|
-
return;
|
|
313
|
-
}
|
|
314
|
-
if (req.method === 'POST' && req.url === '/env') {
|
|
315
|
-
let body = '';
|
|
316
|
-
req.on('data', chunk => {
|
|
317
|
-
body += chunk.toString();
|
|
318
|
-
});
|
|
319
|
-
req.on('end', async () => {
|
|
320
|
-
try {
|
|
321
|
-
const { content } = JSON.parse(body);
|
|
322
|
-
const envPath = path.join(process.cwd(), '.env');
|
|
323
|
-
// Write the .env file
|
|
324
|
-
fs.writeFileSync(envPath, content || '', 'utf8');
|
|
325
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
326
|
-
res.end(JSON.stringify({
|
|
327
|
-
success: true,
|
|
328
|
-
message: 'Environment variables updated successfully'
|
|
329
|
-
}));
|
|
330
|
-
}
|
|
331
|
-
catch (error) {
|
|
332
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
333
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to update .env file' }));
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
return;
|
|
337
|
-
}
|
|
338
|
-
// Tools endpoints
|
|
339
|
-
if (req.method === 'GET' && req.url === '/tools') {
|
|
340
|
-
try {
|
|
341
|
-
// Read the deploy.json file to get tools
|
|
342
|
-
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
343
|
-
if (fs.existsSync(deployPath)) {
|
|
344
|
-
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
345
|
-
// Handle both new skills array format and legacy tools format
|
|
346
|
-
let tools = deployData.tools || {};
|
|
347
|
-
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
348
|
-
// New format: merge all tools from all skills
|
|
349
|
-
tools = {};
|
|
350
|
-
deployData.skills.forEach((skill) => {
|
|
351
|
-
if (skill.tools && Array.isArray(skill.tools)) {
|
|
352
|
-
skill.tools.forEach((tool) => {
|
|
353
|
-
tools[tool.name] = tool;
|
|
354
|
-
});
|
|
355
|
-
}
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
359
|
-
res.end(JSON.stringify({
|
|
360
|
-
success: true,
|
|
361
|
-
tools: tools
|
|
362
|
-
}));
|
|
363
|
-
}
|
|
364
|
-
else {
|
|
365
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
366
|
-
res.end(JSON.stringify({ success: false, error: 'deploy.json not found' }));
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
catch (error) {
|
|
370
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
371
|
-
res.end(JSON.stringify({ success: false, error: 'Failed to load tools' }));
|
|
372
|
-
}
|
|
373
|
-
return;
|
|
374
|
-
}
|
|
375
|
-
if (req.method === 'POST' && req.url === '/tools/test') {
|
|
376
|
-
let body = '';
|
|
377
|
-
req.on('data', chunk => {
|
|
378
|
-
body += chunk.toString();
|
|
379
|
-
});
|
|
380
|
-
req.on('end', async () => {
|
|
381
|
-
try {
|
|
382
|
-
const { toolName, inputs } = JSON.parse(body);
|
|
383
|
-
// Read deploy.json to get the tool's execute function
|
|
384
|
-
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
385
|
-
if (!fs.existsSync(deployPath)) {
|
|
386
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
387
|
-
res.end(JSON.stringify({ success: false, error: 'deploy.json not found' }));
|
|
388
|
-
return;
|
|
389
|
-
}
|
|
390
|
-
const deployData = JSON.parse(fs.readFileSync(deployPath, 'utf8'));
|
|
391
|
-
let tool = null;
|
|
392
|
-
if (deployData.skills && Array.isArray(deployData.skills)) {
|
|
393
|
-
// New format: search through skills array
|
|
394
|
-
for (const skill of deployData.skills) {
|
|
395
|
-
if (skill.tools && Array.isArray(skill.tools)) {
|
|
396
|
-
tool = skill.tools.find((t) => t.name === toolName);
|
|
397
|
-
if (tool)
|
|
398
|
-
break;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
else {
|
|
403
|
-
// Legacy format: search in tools object
|
|
404
|
-
if (deployData.tools && deployData.tools[toolName]) {
|
|
405
|
-
tool = {
|
|
406
|
-
name: toolName,
|
|
407
|
-
...deployData.tools[toolName]
|
|
408
|
-
};
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
if (!tool) {
|
|
412
|
-
res.writeHead(404, { 'Content-Type': 'application/json' });
|
|
413
|
-
res.end(JSON.stringify({ success: false, error: 'Tool not found' }));
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
// Load environment variables from all sources (.env + yaml)
|
|
417
|
-
const envVars = loadEnvironmentVariables();
|
|
418
|
-
// Decompress and execute the tool
|
|
419
|
-
const { gunzipSync } = await import('zlib');
|
|
420
|
-
const { Buffer } = await import('buffer');
|
|
421
|
-
const { createRequire } = await import('module');
|
|
422
|
-
const vm = await import('vm');
|
|
423
|
-
function decompressCode(compressedCode) {
|
|
424
|
-
const buffer = Buffer.from(compressedCode, 'base64');
|
|
425
|
-
return gunzipSync(buffer).toString('utf8');
|
|
426
|
-
}
|
|
427
|
-
const toolCode = decompressCode(tool.execute);
|
|
428
|
-
// Broadcast tool test start
|
|
429
|
-
wss.clients.forEach((client) => {
|
|
430
|
-
if (client.readyState === 1) {
|
|
431
|
-
client.send(JSON.stringify({
|
|
432
|
-
type: 'log',
|
|
433
|
-
subType: 'info',
|
|
434
|
-
message: `🧪 Testing tool: ${toolName}`,
|
|
435
|
-
timestamp: new Date().toISOString(),
|
|
436
|
-
id: Date.now().toString()
|
|
437
|
-
}));
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
// Create custom console that captures output and sends via WebSocket
|
|
441
|
-
const customConsole = createBroadcastConsole((logData) => {
|
|
442
|
-
console.log('Broadcasting tool log:', logData);
|
|
443
|
-
wss.clients.forEach((client) => {
|
|
444
|
-
if (client.readyState === 1) { // WebSocket.OPEN
|
|
445
|
-
client.send(JSON.stringify(logData));
|
|
446
|
-
}
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
// Execute the tool using the common utility
|
|
450
|
-
const result = await executeTool({
|
|
451
|
-
toolCode,
|
|
452
|
-
inputs,
|
|
453
|
-
apiKey,
|
|
454
|
-
agentId,
|
|
455
|
-
customConsole
|
|
456
|
-
});
|
|
457
|
-
// Broadcast tool test completion
|
|
458
|
-
wss.clients.forEach((client) => {
|
|
459
|
-
if (client.readyState === 1) {
|
|
460
|
-
client.send(JSON.stringify({
|
|
461
|
-
type: 'log',
|
|
462
|
-
subType: 'info',
|
|
463
|
-
message: `✅ Tool test completed: ${toolName}`,
|
|
464
|
-
timestamp: new Date().toISOString(),
|
|
465
|
-
id: (Date.now() + 1).toString()
|
|
466
|
-
}));
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
470
|
-
res.end(JSON.stringify({
|
|
471
|
-
success: true,
|
|
472
|
-
result: result
|
|
473
|
-
}));
|
|
474
|
-
}
|
|
475
|
-
catch (error) {
|
|
476
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
477
|
-
res.end(JSON.stringify({
|
|
478
|
-
success: false,
|
|
479
|
-
error: error.message || 'Tool execution failed'
|
|
480
|
-
}));
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
|
-
if (req.method === 'GET' && req.url === '/') {
|
|
486
|
-
// Read the React app HTML template from dist directory
|
|
487
|
-
const htmlTemplate = fs.readFileSync(path.join(__dirname, '..', 'web', 'index.html'), 'utf8');
|
|
488
|
-
// Replace placeholders with actual values
|
|
489
|
-
const html = htmlTemplate
|
|
490
|
-
.replace('{{API_KEY}}', apiKey)
|
|
491
|
-
.replace('{{AGENT_ID}}', agentId)
|
|
492
|
-
.replace('{{SKILL_ID}}', skillId)
|
|
493
|
-
.replace('{{SANDBOX_ID}}', sandboxId);
|
|
494
|
-
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
495
|
-
res.end(html);
|
|
496
|
-
return;
|
|
497
|
-
}
|
|
498
|
-
// Serve the React app bundle
|
|
499
|
-
if (req.method === 'GET' && req.url === '/app.js') {
|
|
500
|
-
try {
|
|
501
|
-
const appJs = fs.readFileSync(path.join(__dirname, '..', 'web', 'app.js'), 'utf8');
|
|
502
|
-
res.writeHead(200, { 'Content-Type': 'application/javascript' });
|
|
503
|
-
res.end(appJs);
|
|
504
|
-
}
|
|
505
|
-
catch (error) {
|
|
506
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
507
|
-
res.end('React app not found. Please run the build process.');
|
|
508
|
-
}
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
// Serve the CSS files
|
|
512
|
-
if (req.method === 'GET' && req.url === '/app.css') {
|
|
513
|
-
try {
|
|
514
|
-
const appCss = fs.readFileSync(path.join(__dirname, '..', 'web', 'app.css'), 'utf8');
|
|
515
|
-
res.writeHead(200, { 'Content-Type': 'text/css' });
|
|
516
|
-
res.end(appCss);
|
|
517
|
-
}
|
|
518
|
-
catch (error) {
|
|
519
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
520
|
-
res.end('CSS not found');
|
|
521
|
-
}
|
|
522
|
-
return;
|
|
523
|
-
}
|
|
524
|
-
if (req.method === 'GET' && req.url === '/tools-page.css') {
|
|
525
|
-
try {
|
|
526
|
-
const toolsPageCss = fs.readFileSync(path.join(__dirname, '..', 'web', 'tools-page.css'), 'utf8');
|
|
527
|
-
res.writeHead(200, { 'Content-Type': 'text/css' });
|
|
528
|
-
res.end(toolsPageCss);
|
|
529
|
-
}
|
|
530
|
-
catch (error) {
|
|
531
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
532
|
-
res.end('Tools page CSS not found');
|
|
533
|
-
}
|
|
534
|
-
return;
|
|
535
|
-
}
|
|
536
|
-
res.writeHead(404);
|
|
537
|
-
res.end('Not Found');
|
|
538
|
-
});
|
|
539
|
-
// Create WebSocket server for log streaming
|
|
540
|
-
const wss = new WebSocketServer({ server });
|
|
541
|
-
wss.on('connection', (ws) => {
|
|
542
|
-
console.log('WebSocket client connected for log streaming');
|
|
543
|
-
ws.on('close', () => {
|
|
544
|
-
console.log('WebSocket client disconnected');
|
|
545
|
-
});
|
|
546
|
-
ws.on('error', (error) => {
|
|
547
|
-
console.error('WebSocket error:', error);
|
|
548
|
-
});
|
|
549
|
-
// Send initial connection message
|
|
550
|
-
ws.send(JSON.stringify({
|
|
551
|
-
type: 'log',
|
|
552
|
-
subType: 'info',
|
|
553
|
-
message: 'Connected to CLI dev server',
|
|
554
|
-
timestamp: new Date().toISOString()
|
|
555
|
-
}));
|
|
556
|
-
});
|
|
557
|
-
server.listen(port, () => {
|
|
558
|
-
console.log('Chat interface available at: http://localhost:' + port);
|
|
559
|
-
console.log('Log streaming WebSocket available at: ws://localhost:' + port);
|
|
560
|
-
});
|
|
561
|
-
// Function to broadcast logs to all connected clients
|
|
562
|
-
const broadcastLog = (message, subType = 'info') => {
|
|
563
|
-
const logMessage = {
|
|
564
|
-
type: 'log',
|
|
565
|
-
subType,
|
|
566
|
-
message,
|
|
567
|
-
timestamp: new Date().toISOString(),
|
|
568
|
-
id: Date.now().toString()
|
|
569
|
-
};
|
|
570
|
-
wss.clients.forEach((client) => {
|
|
571
|
-
if (client.readyState === 1) { // WebSocket.OPEN
|
|
572
|
-
client.send(JSON.stringify(logMessage));
|
|
573
|
-
}
|
|
574
|
-
});
|
|
575
|
-
};
|
|
576
|
-
return { server, wss, broadcastLog };
|
|
577
|
-
}
|
|
578
|
-
// Function to update existing sandbox version
|
|
579
|
-
export async function updateDevVersion(apiKey, agentId, skillId, sandboxVersionId, versionData) {
|
|
580
|
-
try {
|
|
581
|
-
// console.log('Calling UPDATE endpoint for sandbox version');
|
|
582
|
-
const response = await ApiService.Skill.updateDevSkill(apiKey, agentId, skillId, sandboxVersionId, versionData);
|
|
583
|
-
if (response.success) {
|
|
584
|
-
return {
|
|
585
|
-
success: true,
|
|
586
|
-
data: response.data
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
else {
|
|
590
|
-
return {
|
|
591
|
-
success: false,
|
|
592
|
-
error: {
|
|
593
|
-
message: response.error?.message || 'Unknown error',
|
|
594
|
-
error: response.error?.message || 'Unknown error',
|
|
595
|
-
statusCode: response.error?.statusCode || 500
|
|
596
|
-
}
|
|
597
|
-
};
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
catch (error) {
|
|
601
|
-
console.error("Network error updating dev version:", error);
|
|
602
|
-
return {
|
|
603
|
-
success: false,
|
|
604
|
-
error: {
|
|
605
|
-
message: "Network error",
|
|
606
|
-
error: error instanceof Error ? error.message : "Failed to connect to server",
|
|
607
|
-
statusCode: 500
|
|
608
|
-
}
|
|
609
|
-
};
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
// Function to create new sandbox version
|
|
613
|
-
export async function pushDevVersion(apiKey, agentId, skillId, versionData) {
|
|
614
|
-
try {
|
|
615
|
-
// console.log(`🔗 Calling CREATE endpoint for sandbox version`);
|
|
616
|
-
const response = await ApiService.Skill.pushDevSkill(apiKey, agentId, skillId, versionData);
|
|
617
|
-
if (response.success) {
|
|
618
|
-
return {
|
|
619
|
-
success: true,
|
|
620
|
-
data: response.data
|
|
621
|
-
};
|
|
622
|
-
}
|
|
623
|
-
else {
|
|
624
|
-
return {
|
|
625
|
-
success: false,
|
|
626
|
-
error: {
|
|
627
|
-
message: response.error?.message || 'Unknown error',
|
|
628
|
-
error: response.error?.message || 'Unknown error',
|
|
629
|
-
statusCode: response.error?.statusCode || 500
|
|
630
|
-
}
|
|
631
|
-
};
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
catch (error) {
|
|
635
|
-
console.error("❌ Network error pushing dev version:", error);
|
|
636
|
-
return {
|
|
637
|
-
success: false,
|
|
638
|
-
error: {
|
|
639
|
-
message: "Network error",
|
|
640
|
-
error: error instanceof Error ? error.message : "Failed to connect to server",
|
|
641
|
-
statusCode: 500
|
|
642
|
-
}
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
function readConfigVersion() {
|
|
647
|
-
const config = readSkillConfig();
|
|
648
|
-
return config?.skill?.version || null;
|
|
649
|
-
}
|
|
650
|
-
function readDeployJson() {
|
|
651
|
-
const deployPath = path.join(process.cwd(), '.lua', 'deploy.json');
|
|
652
|
-
if (!fs.existsSync(deployPath)) {
|
|
653
|
-
return null;
|
|
654
|
-
}
|
|
655
|
-
const deployContent = fs.readFileSync(deployPath, 'utf8');
|
|
656
|
-
return JSON.parse(deployContent);
|
|
657
|
-
}
|
|
658
|
-
// Function to push multiple skills to sandbox
|
|
659
|
-
async function pushSkillsToSandbox(apiKey, agentId, deployData, isInitial = false) {
|
|
660
|
-
const sandboxIds = {};
|
|
661
|
-
if (!deployData.skills || !Array.isArray(deployData.skills)) {
|
|
662
|
-
throw new Error("No skills found in deploy data");
|
|
663
|
-
}
|
|
664
|
-
for (const skill of deployData.skills) {
|
|
665
|
-
if (!skill.skillId) {
|
|
666
|
-
console.warn(`⚠️ Skipping skill ${skill.name} - no skillId found`);
|
|
667
|
-
continue;
|
|
668
|
-
}
|
|
669
|
-
try {
|
|
670
|
-
const success = await pushSingleSkillToSandbox(apiKey, agentId, skill.skillId, skill, isInitial);
|
|
671
|
-
if (success) {
|
|
672
|
-
// Get the sandbox ID for this skill (stored in .lua directory)
|
|
673
|
-
const sandboxId = await getSandboxSkillId(skill.name);
|
|
674
|
-
if (sandboxId) {
|
|
675
|
-
sandboxIds[skill.name] = sandboxId;
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
|
-
catch (error) {
|
|
680
|
-
console.error(`❌ Failed to push skill ${skill.name}:`, error);
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
return sandboxIds;
|
|
684
|
-
}
|
|
685
|
-
// Function to push a single skill to sandbox (extracted for reuse)
|
|
686
|
-
async function pushSingleSkillToSandbox(apiKey, agentId, skillId, skillData, isInitial = false) {
|
|
687
|
-
const skillName = skillData.name || 'Unknown Skill';
|
|
688
|
-
const sandboxSkillId = await getSandboxSkillId(skillName);
|
|
689
|
-
// Load environment variables
|
|
690
|
-
const envVars = loadEnvironmentVariables();
|
|
691
|
-
// console.log(skillData);
|
|
692
|
-
const payloadWithNameAndEnv = {
|
|
693
|
-
...skillData,
|
|
694
|
-
name: skillName,
|
|
695
|
-
env: envVars
|
|
696
|
-
};
|
|
697
|
-
if (sandboxSkillId) {
|
|
698
|
-
// Try to update existing sandbox version
|
|
699
|
-
if (!isInitial) {
|
|
700
|
-
writeProgress("🔄 Updating existing sandbox version...");
|
|
701
|
-
}
|
|
702
|
-
const updateResult = await updateDevVersion(apiKey, agentId, skillId, sandboxSkillId, payloadWithNameAndEnv);
|
|
703
|
-
if (updateResult.success && updateResult.data) {
|
|
704
|
-
if (!isInitial) {
|
|
705
|
-
// writeSuccess(`✅ Version ${updateResult.data.version} updated in sandbox successfully`);
|
|
706
|
-
// writeSuccess(`🔑 Sandbox Skill ID: ${updateResult.data.skillId}`);
|
|
707
|
-
}
|
|
708
|
-
return true;
|
|
709
|
-
}
|
|
710
|
-
else if (updateResult.error) {
|
|
711
|
-
writeProgress("⚠️ Failed to update existing sandbox, creating new one...");
|
|
712
|
-
console.error(`❌ Sandbox update failed: ${updateResult.error.message}`);
|
|
713
|
-
if (updateResult.error.error) {
|
|
714
|
-
console.error(` Details: ${updateResult.error.error}`);
|
|
715
|
-
}
|
|
716
|
-
// If skill not found during update, give helpful guidance before trying to create
|
|
717
|
-
if (updateResult.error.message.includes('Skill not found') || updateResult.error.statusCode === 400 || updateResult.error.statusCode === 404) {
|
|
718
|
-
console.error('\n💡 The skill doesn\'t exist on the server.');
|
|
719
|
-
console.error(' Please run "lua push" first to deploy your skill, then try "lua dev" again.\n');
|
|
720
|
-
}
|
|
721
|
-
// Fall through to create new sandbox
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
// Create new sandbox version (either no existing ID or update failed)
|
|
725
|
-
if (!isInitial) {
|
|
726
|
-
writeProgress("🔄 Creating new sandbox version...");
|
|
727
|
-
}
|
|
728
|
-
const result = await pushDevVersion(apiKey, agentId, skillId, payloadWithNameAndEnv);
|
|
729
|
-
if (result.success && result.data) {
|
|
730
|
-
// Store the new sandbox skill ID
|
|
731
|
-
await setSandboxSkillId(result.data.skillId, skillName);
|
|
732
|
-
if (!isInitial) {
|
|
733
|
-
writeSuccess(`✅ Version ${result.data.version} pushed to sandbox successfully`);
|
|
734
|
-
writeSuccess(`🔑 Sandbox Skill ID: ${result.data.skillId}`);
|
|
735
|
-
}
|
|
736
|
-
return true;
|
|
737
|
-
}
|
|
738
|
-
else if (result.error) {
|
|
739
|
-
console.error(`❌ Sandbox creation failed: ${result.error.message}`);
|
|
740
|
-
if (result.error.error) {
|
|
741
|
-
console.error(` Details: ${result.error.error}`);
|
|
742
|
-
}
|
|
743
|
-
if (result.error.statusCode) {
|
|
744
|
-
console.error(` Status Code: ${result.error.statusCode}`);
|
|
745
|
-
}
|
|
746
|
-
// If skill not found, give helpful guidance
|
|
747
|
-
if (result.error.message.includes('Skill not found') || result.error.statusCode === 400 || result.error.statusCode === 404) {
|
|
748
|
-
console.error('\n💡 The skill hasn\'t been deployed to the server yet.');
|
|
749
|
-
console.error(' Please run "lua push" first to deploy your skill, then try "lua dev" again.');
|
|
750
|
-
}
|
|
751
|
-
return false;
|
|
752
|
-
}
|
|
753
|
-
else {
|
|
754
|
-
console.error("❌ Failed to push version to sandbox. Please try again.");
|
|
755
|
-
return false;
|
|
756
|
-
}
|
|
757
|
-
}
|
|
10
|
+
import { pushSkillsToSandbox } from '../utils/dev-api.js';
|
|
11
|
+
import { createChatServer } from '../utils/dev-server.js';
|
|
12
|
+
import { createFileWatcher } from '../utils/dev-watcher.js';
|
|
13
|
+
import { readConfigVersion, readDeployJson, extractSkillId, validateConfig, validateDeployData, validateAgentConfig, } from '../utils/dev-helpers.js';
|
|
14
|
+
import { DEV_SERVER_PORT } from '../config/dev.constants.js';
|
|
15
|
+
/**
|
|
16
|
+
* Main dev command - starts development mode with live reloading.
|
|
17
|
+
*
|
|
18
|
+
* This command performs the following steps:
|
|
19
|
+
* 1. Validates configuration and authentication
|
|
20
|
+
* 2. Compiles the skill
|
|
21
|
+
* 3. Pushes all skills to sandbox environment
|
|
22
|
+
* 4. Starts web server with chat interface and tool testing
|
|
23
|
+
* 5. Opens browser to chat interface
|
|
24
|
+
* 6. Watches for file changes and auto-recompiles
|
|
25
|
+
*
|
|
26
|
+
* Features:
|
|
27
|
+
* - Live chat interface for testing skills
|
|
28
|
+
* - Real-time tool testing with WebSocket log streaming
|
|
29
|
+
* - Automatic recompilation and push on file changes
|
|
30
|
+
* - Environment variable management
|
|
31
|
+
* - Persona configuration
|
|
32
|
+
* - Multi-skill support
|
|
33
|
+
*
|
|
34
|
+
* @returns Promise that resolves when dev mode is stopped (never resolves normally)
|
|
35
|
+
*/
|
|
758
36
|
export async function devCommand() {
|
|
759
37
|
return withErrorHandling(async () => {
|
|
760
|
-
//
|
|
38
|
+
// Step 1: Validate configuration
|
|
761
39
|
const config = readSkillConfig();
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
}
|
|
766
|
-
// Read version from config (handle both old and new formats)
|
|
767
|
-
let version = config.skill?.version; // Legacy format
|
|
768
|
-
if (!version && config.skills && config.skills.length > 0) {
|
|
769
|
-
version = config.skills[0].version; // New format - use first skill's version
|
|
770
|
-
}
|
|
771
|
-
if (!version) {
|
|
772
|
-
version = "1.0.0"; // Default version
|
|
773
|
-
}
|
|
774
|
-
// Load API key
|
|
40
|
+
validateConfig(config);
|
|
41
|
+
const version = readConfigVersion(config);
|
|
42
|
+
// Step 2: Authenticate
|
|
775
43
|
const apiKey = await loadApiKey();
|
|
776
44
|
if (!apiKey) {
|
|
777
45
|
console.error("❌ No API key found. Please run 'lua auth configure' to set up your API key.");
|
|
778
46
|
process.exit(1);
|
|
779
47
|
}
|
|
780
|
-
// Validate API key
|
|
781
48
|
const userData = await checkApiKey(apiKey);
|
|
782
49
|
writeProgress("✅ Authenticated");
|
|
783
|
-
// Compile the skill
|
|
50
|
+
// Step 3: Compile the skill
|
|
784
51
|
writeProgress("🔄 Compiling skill...");
|
|
785
52
|
await compileCommand();
|
|
786
|
-
//
|
|
53
|
+
// Step 4: Read and validate compiled output
|
|
787
54
|
const updatedConfig = readSkillConfig();
|
|
788
55
|
if (!updatedConfig) {
|
|
789
56
|
console.error("❌ Failed to read updated skill configuration after compilation.");
|
|
790
57
|
process.exit(1);
|
|
791
58
|
}
|
|
792
|
-
// Read deploy.json
|
|
793
59
|
const deployData = readDeployJson();
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
if (!deployData.skills || !Array.isArray(deployData.skills) || deployData.skills.length === 0) {
|
|
800
|
-
console.error("❌ No skills found in deploy.json. Compilation may have failed.");
|
|
801
|
-
process.exit(1);
|
|
802
|
-
}
|
|
803
|
-
// Extract agentId from updated config
|
|
804
|
-
const agentId = updatedConfig.agent?.agentId;
|
|
805
|
-
if (!agentId) {
|
|
806
|
-
console.error("❌ Missing agentId in skill configuration");
|
|
807
|
-
process.exit(1);
|
|
808
|
-
}
|
|
809
|
-
// For multi-skill projects, we'll use the first skill's ID for sandbox
|
|
810
|
-
let skillId = updatedConfig.skill?.skillId; // Legacy format
|
|
811
|
-
if (!skillId && updatedConfig.skills && updatedConfig.skills.length > 0) {
|
|
812
|
-
skillId = updatedConfig.skills[0].skillId; // New format - use first skill
|
|
813
|
-
}
|
|
60
|
+
validateDeployData(deployData);
|
|
61
|
+
// Step 5: Extract configuration values
|
|
62
|
+
validateAgentConfig(updatedConfig);
|
|
63
|
+
const agentId = updatedConfig.agent.agentId;
|
|
64
|
+
const skillId = extractSkillId(updatedConfig);
|
|
814
65
|
if (!skillId) {
|
|
815
66
|
console.error("❌ No skillId found after compilation. Skill creation may have failed.");
|
|
816
67
|
console.error("Available skills:", updatedConfig.skills);
|
|
817
68
|
process.exit(1);
|
|
818
69
|
}
|
|
819
|
-
//
|
|
70
|
+
// Step 6: Push skills to sandbox
|
|
820
71
|
writeProgress("🔄 Pushing skills to sandbox...");
|
|
821
|
-
console.log('deployData', deployData);
|
|
822
72
|
const sandboxIds = await pushSkillsToSandbox(apiKey, agentId, deployData, true);
|
|
823
|
-
// console.log(sandboxIds);
|
|
824
73
|
if (Object.keys(sandboxIds).length === 0) {
|
|
825
74
|
console.error("❌ Failed to push any skills to sandbox. Cannot start development mode.");
|
|
826
75
|
process.exit(1);
|
|
@@ -833,100 +82,31 @@ export async function devCommand() {
|
|
|
833
82
|
console.error("❌ No sandbox skill ID found. Cannot start chat interface.");
|
|
834
83
|
process.exit(1);
|
|
835
84
|
}
|
|
836
|
-
// Start web server for chat interface
|
|
837
|
-
const
|
|
838
|
-
|
|
839
|
-
// Open browser to chat interface
|
|
85
|
+
// Step 7: Start web server for chat interface
|
|
86
|
+
const { server, wss, broadcastLog } = createChatServer(apiKey, agentId, skillId, sandboxSkillId, DEV_SERVER_PORT);
|
|
87
|
+
// Step 8: Open browser to chat interface
|
|
840
88
|
try {
|
|
841
|
-
await open(`http://localhost:${
|
|
89
|
+
await open(`http://localhost:${DEV_SERVER_PORT}`);
|
|
842
90
|
writeSuccess("🌐 Chat interface opened in your browser");
|
|
843
91
|
broadcastLog("🌐 Chat interface opened in your browser", 'info');
|
|
844
92
|
}
|
|
845
93
|
catch (error) {
|
|
846
|
-
writeSuccess(`🌐 Chat interface available at: http://localhost:${
|
|
847
|
-
broadcastLog(`🌐 Chat interface available at: http://localhost:${
|
|
94
|
+
writeSuccess(`🌐 Chat interface available at: http://localhost:${DEV_SERVER_PORT}`);
|
|
95
|
+
broadcastLog(`🌐 Chat interface available at: http://localhost:${DEV_SERVER_PORT}`, 'info');
|
|
848
96
|
}
|
|
849
|
-
// Start file watching
|
|
97
|
+
// Step 9: Start file watching
|
|
850
98
|
writeSuccess("🔍 Watching for file changes... (Press Ctrl+C to stop)");
|
|
851
99
|
broadcastLog("🔍 Watching for file changes... (Press Ctrl+C to stop)", 'info');
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
if (filename && (filename.includes('.lua/') ||
|
|
858
|
-
filename.includes('.lua\\') ||
|
|
859
|
-
filename.includes('node_modules/') ||
|
|
860
|
-
filename.includes('node_modules\\') ||
|
|
861
|
-
filename.includes('.git/') ||
|
|
862
|
-
filename.includes('.git\\') ||
|
|
863
|
-
filename.endsWith('.log') ||
|
|
864
|
-
filename.endsWith('.tmp') ||
|
|
865
|
-
filename.endsWith('.js') ||
|
|
866
|
-
filename.endsWith('.map') ||
|
|
867
|
-
filename.includes('dist/') ||
|
|
868
|
-
filename.includes('dist\\'))) {
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
// Debounce rapid changes
|
|
872
|
-
if (isCompiling) {
|
|
873
|
-
pendingCompile = true;
|
|
874
|
-
return;
|
|
875
|
-
}
|
|
876
|
-
// Clear any existing timeout
|
|
877
|
-
if (compileTimeout) {
|
|
878
|
-
clearTimeout(compileTimeout);
|
|
879
|
-
}
|
|
880
|
-
// Debounce file changes with a 500ms delay
|
|
881
|
-
compileTimeout = setTimeout(async () => {
|
|
882
|
-
if (isCompiling) {
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
isCompiling = true;
|
|
886
|
-
pendingCompile = false;
|
|
887
|
-
try {
|
|
888
|
-
writeProgress(`🔄 File changed: ${filename} - Compiling and pushing...`);
|
|
889
|
-
broadcastLog(`🔄 File changed: ${filename} - Compiling and pushing...`, 'info');
|
|
890
|
-
// Compile the skill
|
|
891
|
-
await compileCommand();
|
|
892
|
-
broadcastLog("✅ Compilation completed", 'info');
|
|
893
|
-
// Read updated deploy.json
|
|
894
|
-
const updatedDeployData = readDeployJson();
|
|
895
|
-
if (!updatedDeployData) {
|
|
896
|
-
writeProgress("❌ Compilation failed, skipping push");
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
// Verify updated deploy.json has skills
|
|
900
|
-
if (!updatedDeployData.skills || !Array.isArray(updatedDeployData.skills) || updatedDeployData.skills.length === 0) {
|
|
901
|
-
writeProgress("❌ No skills found in updated deploy.json, skipping push");
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
// Push all skills to sandbox
|
|
905
|
-
const updatedSandboxIds = await pushSkillsToSandbox(apiKey, agentId, updatedDeployData, false);
|
|
906
|
-
if (Object.keys(updatedSandboxIds).length === 0) {
|
|
907
|
-
writeProgress("❌ Failed to push any skills to sandbox, will retry on next change");
|
|
908
|
-
broadcastLog("❌ Failed to push skills to sandbox, will retry on next change", 'error');
|
|
909
|
-
}
|
|
910
|
-
else {
|
|
911
|
-
// writeProgress(`✅ Successfully pushed ${Object.keys(updatedSandboxIds).length} skills to sandbox`);
|
|
912
|
-
broadcastLog(`✅ Successfully pushed ${Object.keys(updatedSandboxIds).length} skills to sandbox`, 'info');
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
catch (error) {
|
|
916
|
-
writeProgress(`❌ Error during auto-compile: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
917
|
-
}
|
|
918
|
-
finally {
|
|
919
|
-
isCompiling = false;
|
|
920
|
-
}
|
|
921
|
-
}, 500); // 500ms debounce delay
|
|
100
|
+
const { watcher, cleanup } = createFileWatcher({
|
|
101
|
+
apiKey,
|
|
102
|
+
agentId,
|
|
103
|
+
readDeployJson,
|
|
104
|
+
broadcastLog,
|
|
922
105
|
});
|
|
923
|
-
// Handle graceful shutdown
|
|
106
|
+
// Step 10: Handle graceful shutdown
|
|
924
107
|
process.on('SIGINT', () => {
|
|
925
108
|
writeSuccess("\n🛑 Stopping file watcher...");
|
|
926
|
-
|
|
927
|
-
clearTimeout(compileTimeout);
|
|
928
|
-
}
|
|
929
|
-
watcher.close();
|
|
109
|
+
cleanup();
|
|
930
110
|
process.exit(0);
|
|
931
111
|
});
|
|
932
112
|
// Keep the process alive
|