luxlabs 1.0.21 → 1.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/README.md +16 -21
  2. package/commands/ab-tests.js +14 -11
  3. package/commands/agents.js +11 -11
  4. package/commands/data.js +19 -17
  5. package/commands/deploy.js +145 -82
  6. package/commands/flows.js +152 -133
  7. package/commands/interface/init.js +36 -35
  8. package/commands/interface.js +135 -10
  9. package/commands/knowledge.js +3 -3
  10. package/commands/list.js +6 -24
  11. package/commands/login.js +31 -26
  12. package/commands/logout.js +13 -4
  13. package/commands/logs.js +17 -66
  14. package/commands/project.js +74 -47
  15. package/commands/secrets.js +1 -1
  16. package/commands/servers.js +9 -113
  17. package/commands/storage.js +1 -1
  18. package/commands/tools.js +4 -4
  19. package/commands/validate-data-lux.js +5 -2
  20. package/commands/voice-agents.js +22 -18
  21. package/lib/config.js +235 -83
  22. package/lib/helpers.js +6 -4
  23. package/lux.js +4 -94
  24. package/package.json +6 -1
  25. package/templates/interface-boilerplate/components/auth/sign-in-form.tsx +41 -34
  26. package/templates/interface-boilerplate/components/auth/sign-up-form.tsx +41 -34
  27. package/templates/interface-boilerplate/components/providers/posthog-provider.tsx +41 -26
  28. package/templates/interface-boilerplate/gitignore.template +4 -0
  29. package/templates/interface-boilerplate/lib/auth.config.ts +3 -2
  30. package/templates/interface-boilerplate/lib/knowledge.ts +2 -2
  31. package/templates/interface-boilerplate/middleware.ts +14 -3
  32. package/templates/interface-boilerplate/next-env.d.ts +6 -0
  33. package/templates/interface-boilerplate/package-lock.json +432 -8
  34. package/commands/dev.js +0 -578
  35. package/commands/init.js +0 -126
  36. package/commands/link.js +0 -127
  37. package/commands/up.js +0 -211
package/commands/link.js DELETED
@@ -1,127 +0,0 @@
1
- const axios = require('axios');
2
- const chalk = require('chalk');
3
- const ora = require('ora');
4
- const {
5
- saveInterfaceConfig,
6
- loadInterfaceConfig,
7
- getApiUrl,
8
- getAuthHeaders,
9
- isAuthenticated,
10
- } = require('../lib/config');
11
-
12
- async function link(interfaceId) {
13
- // Check authentication
14
- if (!isAuthenticated()) {
15
- console.log(
16
- chalk.red('❌ Not authenticated. Run'),
17
- chalk.white('lux login'),
18
- chalk.red('first.')
19
- );
20
- process.exit(1);
21
- }
22
-
23
- if (!interfaceId) {
24
- console.log(chalk.red('❌ Interface ID required.'));
25
- console.log(chalk.dim('Usage:'), chalk.white('lux link <interface-id>'));
26
- process.exit(1);
27
- }
28
-
29
- // Check if already linked
30
- const existing = loadInterfaceConfig();
31
- if (existing && existing.id) {
32
- console.log(
33
- chalk.yellow('⚠️ Already linked to:'),
34
- existing.name,
35
- chalk.dim(`(${existing.id})`)
36
- );
37
-
38
- const inquirer = require('inquirer');
39
- const { confirm } = await inquirer.prompt([
40
- {
41
- type: 'confirm',
42
- name: 'confirm',
43
- message: 'Do you want to relink to a different interface?',
44
- default: false,
45
- },
46
- ]);
47
-
48
- if (!confirm) {
49
- console.log(chalk.dim('Cancelled.'));
50
- return;
51
- }
52
- }
53
-
54
- const apiUrl = getApiUrl();
55
- const spinner = ora('Fetching interface...').start();
56
-
57
- try {
58
- // Fetch interface details
59
- const { data } = await axios.get(
60
- `${apiUrl}/api/interfaces/${interfaceId}`,
61
- {
62
- headers: getAuthHeaders(),
63
- }
64
- );
65
-
66
- const iface = data.interface;
67
-
68
- if (!iface) {
69
- spinner.fail('Interface not found');
70
- process.exit(1);
71
- }
72
-
73
- spinner.succeed(chalk.green('✓ Found interface'));
74
-
75
- // Save config
76
- const config = {
77
- id: iface.id,
78
- name: iface.name,
79
- description: iface.description,
80
- githubRepoUrl: iface.github_repo_url,
81
- deploymentUrl: iface.vercel_deployment_url,
82
- linkedAt: new Date().toISOString(),
83
- };
84
-
85
- saveInterfaceConfig(config);
86
-
87
- console.log(chalk.green('\n✓ Linked successfully!\n'));
88
- console.log(chalk.white(iface.name));
89
- console.log(chalk.dim(iface.description || 'No description'));
90
-
91
- if (iface.vercel_deployment_url) {
92
- console.log(chalk.cyan(`\n${iface.vercel_deployment_url}`));
93
- }
94
-
95
- console.log(chalk.dim('\nYou can now run:'));
96
- console.log(chalk.white(' lux up'), chalk.dim('- Upload changes'));
97
- console.log(
98
- chalk.white(' lux deploy'),
99
- chalk.dim('- Deploy to production')
100
- );
101
- console.log(chalk.white(' lux logs'), chalk.dim('- View logs\n'));
102
- } catch (error) {
103
- spinner.fail('Failed to link');
104
- console.error(
105
- chalk.red('\n❌ Error:'),
106
- error.response?.data?.error || error.message
107
- );
108
-
109
- if (error.response?.status === 401) {
110
- console.log(
111
- chalk.yellow('\nYour session may have expired. Try running:'),
112
- chalk.white('lux login')
113
- );
114
- } else if (error.response?.status === 404) {
115
- console.log(
116
- chalk.yellow('\nInterface not found. Check the ID and try again.')
117
- );
118
- console.log(chalk.dim('List interfaces with:'), chalk.white('lux list'));
119
- }
120
-
121
- process.exit(1);
122
- }
123
- }
124
-
125
- module.exports = {
126
- link,
127
- };
package/commands/up.js DELETED
@@ -1,211 +0,0 @@
1
- const axios = require('axios');
2
- const archiver = require('archiver');
3
- const fs = require('fs');
4
- const path = require('path');
5
- const ora = require('ora');
6
- const chalk = require('chalk');
7
- const ignore = require('ignore');
8
- const {
9
- loadConfig,
10
- loadInterfaceConfig,
11
- saveInterfaceConfig,
12
- getApiUrl,
13
- getAuthHeaders,
14
- isAuthenticated,
15
- } = require('../lib/config');
16
-
17
- async function up(options) {
18
- // Check authentication
19
- if (!isAuthenticated()) {
20
- console.log(
21
- chalk.red('❌ Not authenticated. Run'),
22
- chalk.white('lux login'),
23
- chalk.red('first.')
24
- );
25
- process.exit(1);
26
- }
27
-
28
- // Check if initialized
29
- const interfaceConfig = loadInterfaceConfig();
30
- if (!interfaceConfig) {
31
- console.log(
32
- chalk.red('❌ Not initialized. Run'),
33
- chalk.white('lux init'),
34
- chalk.red('first.')
35
- );
36
- process.exit(1);
37
- }
38
-
39
- const config = loadConfig();
40
- const apiUrl = getApiUrl();
41
- const spinner = ora('Preparing upload...').start();
42
-
43
- try {
44
- let interfaceId = interfaceConfig.id;
45
-
46
- // Step 1: Create interface if it doesn't exist
47
- if (!interfaceId) {
48
- spinner.text = 'Creating interface...';
49
-
50
- const { data } = await axios.post(
51
- `${apiUrl}/api/interfaces`,
52
- {
53
- name: interfaceConfig.name,
54
- description: interfaceConfig.description,
55
- },
56
- {
57
- headers: getAuthHeaders(),
58
- }
59
- );
60
-
61
- interfaceId = data.interface.id;
62
- interfaceConfig.id = interfaceId;
63
- interfaceConfig.githubRepoUrl = data.interface.github_repo_url;
64
- saveInterfaceConfig(interfaceConfig);
65
-
66
- spinner.succeed(chalk.green(`Created interface: ${interfaceId}`));
67
- spinner.start();
68
- }
69
-
70
- // Step 2: Create zip file
71
- spinner.text = 'Creating zip file...';
72
- const zipPath = await createZip(process.cwd());
73
- const stats = fs.statSync(zipPath);
74
- spinner.text = `Created zip (${formatBytes(stats.size)})...`;
75
-
76
- // Step 3: Get presigned upload URL
77
- spinner.text = 'Getting upload URL...';
78
- const { data: urlData } = await axios.post(
79
- `${apiUrl}/api/interfaces/${interfaceId}/presigned-urls`,
80
- { zip_upload: true },
81
- { headers: getAuthHeaders() }
82
- );
83
-
84
- // Step 4: Upload zip to R2
85
- spinner.text = 'Uploading files...';
86
- await axios.put(urlData.upload_url, fs.readFileSync(zipPath), {
87
- headers: { 'Content-Type': 'application/zip' },
88
- maxBodyLength: Infinity,
89
- maxContentLength: Infinity,
90
- onUploadProgress: (progressEvent) => {
91
- const percent = Math.round(
92
- (progressEvent.loaded * 100) / progressEvent.total
93
- );
94
- spinner.text = `Uploading files... ${percent}%`;
95
- },
96
- });
97
-
98
- // Step 5: Trigger extraction and GitHub sync
99
- spinner.text = 'Syncing to GitHub...';
100
- const { data: uploadResult } = await axios.post(
101
- `${apiUrl}/api/interfaces/${interfaceId}/upload-files`,
102
- { zip_path: urlData.storage_path },
103
- { headers: getAuthHeaders() }
104
- );
105
-
106
- // Cleanup
107
- fs.unlinkSync(zipPath);
108
-
109
- spinner.succeed(
110
- chalk.green(`✓ Uploaded ${uploadResult.files_uploaded} files`)
111
- );
112
-
113
- console.log(chalk.dim(`\n${uploadResult.message}\n`));
114
- console.log(chalk.cyan('Files synced to dev branch. Ready to deploy!'));
115
- console.log(
116
- chalk.dim(`Run ${chalk.white('lux deploy')} to publish to production\n`)
117
- );
118
-
119
- if (interfaceConfig.githubRepoUrl) {
120
- console.log(chalk.dim(`GitHub: ${interfaceConfig.githubRepoUrl}`));
121
- }
122
- } catch (error) {
123
- spinner.fail('Upload failed');
124
- console.error(
125
- chalk.red('\n❌ Error:'),
126
- error.response?.data?.error || error.message
127
- );
128
-
129
- if (error.response?.status === 401) {
130
- console.log(
131
- chalk.yellow('\nYour session may have expired. Try running:'),
132
- chalk.white('lux login')
133
- );
134
- }
135
-
136
- process.exit(1);
137
- }
138
- }
139
-
140
- async function createZip(sourceDir) {
141
- const output = fs.createWriteStream('/tmp/lux-upload.zip');
142
- const archive = archiver('zip', { zlib: { level: 9 } });
143
-
144
- // Load .gitignore patterns
145
- const ig = ignore();
146
- const gitignorePath = path.join(sourceDir, '.gitignore');
147
-
148
- if (fs.existsSync(gitignorePath)) {
149
- const gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
150
- ig.add(gitignoreContent);
151
- }
152
-
153
- // Add default ignores (same as server)
154
- ig.add([
155
- 'node_modules/',
156
- '.next/',
157
- '.git/',
158
- '.env.local',
159
- '.DS_Store',
160
- 'dist/',
161
- 'build/',
162
- '.cache/',
163
- 'coverage/',
164
- '.lux/interface.json', // Don't upload local config
165
- ]);
166
-
167
- return new Promise((resolve, reject) => {
168
- output.on('close', () => resolve('/tmp/lux-upload.zip'));
169
- archive.on('error', reject);
170
-
171
- archive.pipe(output);
172
-
173
- // Recursively add files
174
- function addDirectory(dirPath, baseDir = '') {
175
- const files = fs.readdirSync(dirPath);
176
-
177
- for (const file of files) {
178
- const fullPath = path.join(dirPath, file);
179
- const relativePath = path.join(baseDir, file);
180
-
181
- // Check if ignored
182
- if (ig.ignores(relativePath)) {
183
- continue;
184
- }
185
-
186
- const stat = fs.statSync(fullPath);
187
-
188
- if (stat.isDirectory()) {
189
- addDirectory(fullPath, relativePath);
190
- } else if (stat.isFile()) {
191
- archive.file(fullPath, { name: relativePath });
192
- }
193
- }
194
- }
195
-
196
- addDirectory(sourceDir);
197
- archive.finalize();
198
- });
199
- }
200
-
201
- function formatBytes(bytes) {
202
- if (bytes === 0) return '0 Bytes';
203
- const k = 1024;
204
- const sizes = ['Bytes', 'KB', 'MB', 'GB'];
205
- const i = Math.floor(Math.log(bytes) / Math.log(k));
206
- return Math.round((bytes / Math.pow(k, i)) * 100) / 100 + ' ' + sizes[i];
207
- }
208
-
209
- module.exports = {
210
- up,
211
- };