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/flows.js CHANGED
@@ -27,6 +27,34 @@ const {
27
27
  // Webhook helper functions
28
28
  const WEBHOOK_WORKER_URL = 'https://webhook-trigger-worker.jason-a5d.workers.dev';
29
29
 
30
+ /**
31
+ * Resolve a flow name-or-id to the actual flow ID.
32
+ * Supports case-insensitive partial matching against both flow ID and name.
33
+ */
34
+ function resolveFlowId(nameOrId) {
35
+ if (!nameOrId) return null;
36
+
37
+ const localFlows = listLocalFlows();
38
+ if (localFlows.length === 0) return nameOrId; // Fall through to let caller handle not-found
39
+
40
+ const search = nameOrId.toLowerCase();
41
+
42
+ // 1. Exact match on ID
43
+ const exact = localFlows.find(f => f.id === nameOrId);
44
+ if (exact) return exact.id;
45
+
46
+ // 2. Case-insensitive partial match on ID
47
+ const idMatch = localFlows.find(f => f.id.toLowerCase().includes(search));
48
+ if (idMatch) return idMatch.id;
49
+
50
+ // 3. Case-insensitive partial match on name
51
+ const nameMatch = localFlows.find(f => f.name && f.name.toLowerCase().includes(search));
52
+ if (nameMatch) return nameMatch.id;
53
+
54
+ // No match found — return the original input so the caller can show a proper error
55
+ return nameOrId;
56
+ }
57
+
30
58
  /**
31
59
  * Get webhook token for a workflow
32
60
  */
@@ -78,7 +106,7 @@ async function handleFlows(args) {
78
106
  // Check authentication
79
107
  if (!isAuthenticated()) {
80
108
  console.log(
81
- chalk.red('Not authenticated. Run'),
109
+ chalk.red('Not authenticated. Run'),
82
110
  chalk.white('lux login'),
83
111
  chalk.red('first.')
84
112
  );
@@ -93,20 +121,28 @@ ${chalk.bold('Usage:')} lux flows <command> [args]
93
121
 
94
122
  ${chalk.bold('Commands:')}
95
123
  list List all flows (from local storage)
96
- get <id> Get flow details with config
97
- status <id> Show sync status for a flow
124
+ get <name-or-id> Get flow details with config
125
+ status <name-or-id> Show sync status for a flow
98
126
  create <name> [desc] [--publish] Create flow (use --publish to publish immediately)
99
- init <name> [desc] [--publish] Initialize flow (alias for create)
100
- save <id> <config-file> Save draft config from file (local)
127
+ save <name-or-id> <config-file> Save draft config from file (local)
101
128
  sync Sync published flows from cloud
102
- publish <id> Publish flow to cloud
103
- delete <id> Delete a local flow
104
- diff <id> Show local vs published differences
129
+ publish <name-or-id> Publish flow to cloud
130
+ delete <name-or-id> Delete a local flow
131
+ diff <name-or-id> Show local vs published differences
132
+
133
+ ${chalk.bold('Webhook Commands:')}
134
+ webhook-url <name-or-id> Get webhook URL and status
135
+ webhook-listen <name-or-id> Start listening session for webhook capture
136
+ webhook-poll <name-or-id> Check for captured webhook payload
137
+ webhook-accept <name-or-id> Accept webhook format and save variables
138
+ webhook-decline <name-or-id> Decline webhook and reset session
105
139
 
106
- ${chalk.bold('Execution History:')}
107
- executions <flow-id> [--limit N] List execution history for a flow
108
- execution <flow-id> <exec-id> Get full execution details
109
- node <flow-id> <exec-id> <node-id> Get specific node execution details
140
+ ${chalk.bold('Execution Commands:')}
141
+ executions <name-or-id> [--limit N] List recent executions
142
+ execution <name-or-id> <exec-id> Get execution details
143
+ node <name-or-id> <exec-id> <node-id> Get node execution details
144
+ test <name-or-id> [--data <json>] Test a flow with sample data
145
+ last <name-or-id> Show the last execution result
110
146
 
111
147
  ${chalk.bold('Sync Status:')}
112
148
  draft - Never published, local only
@@ -114,47 +150,30 @@ ${chalk.bold('Sync Status:')}
114
150
  dirty - Has local changes since publish
115
151
  conflict - Local changes + cloud has newer version
116
152
 
117
- ${chalk.bold('Webhook Commands:')}
118
- webhook-url <id> Get webhook URL and status
119
- webhook-listen <id> Start listening session for webhook capture
120
- webhook-poll <id> Check for captured webhook payload
121
- webhook-accept <id> Accept webhook format and save variables
122
- webhook-decline <id> Decline webhook and reset session
123
-
124
- ${chalk.bold('Execution Commands:')}
125
- executions <id> List recent executions for a flow
126
- execution <id> <exec-id> Get details of a specific execution
127
- test <id> [--data] Test a flow with sample data
128
- last <id> Show the last execution result
129
-
130
153
  ${chalk.bold('Examples:')}
131
154
  lux flows list
132
- lux flows get flow_123
133
- lux flows status flow_123
155
+ lux flows get "My Flow"
156
+ lux flows status my-flow
134
157
  lux flows create "My Flow" "Description"
135
- lux flows create "My Flow" --publish # Create and publish immediately
136
- lux flows init "My Flow" --publish
137
- lux flows save flow_123 ./config.json
158
+ lux flows create "My Flow" --publish
159
+ lux flows save my-flow ./config.json
138
160
  lux flows sync
139
- lux flows publish flow_123
140
- lux flows diff flow_123
161
+ lux flows publish my-flow
162
+ lux flows diff my-flow
141
163
 
142
- ${chalk.bold('Execution history:')}
143
- lux flows executions my-flow-id
144
- lux flows executions my-flow-id --limit 50
145
- lux flows execution my-flow-id exec_abc123
146
- lux flows node my-flow-id exec_abc123 node-1
164
+ ${chalk.bold('Execution:')}
165
+ lux flows executions my-flow
166
+ lux flows executions my-flow --limit 50
167
+ lux flows execution my-flow exec_abc123
168
+ lux flows node my-flow exec_abc123 node-1
169
+ lux flows last my-flow
170
+ lux flows test my-flow --data '{"name":"test"}'
147
171
 
148
172
  ${chalk.bold('Webhook:')}
149
- lux flows webhook-url flow_123
150
- lux flows webhook-listen flow_123
151
- lux flows webhook-poll flow_123
152
- lux flows webhook-accept flow_123
153
-
154
- ${chalk.bold('Execution debugging:')}
155
- lux flows executions my-flow # List recent executions
156
- lux flows last my-flow # Show last execution result
157
- lux flows test my-flow --data '{"name":"test"}' # Test with data
173
+ lux flows webhook-url my-flow
174
+ lux flows webhook-listen my-flow
175
+ lux flows webhook-poll my-flow
176
+ lux flows webhook-accept my-flow
158
177
  `);
159
178
  process.exit(0);
160
179
  }
@@ -203,12 +222,12 @@ ${chalk.bold('Examples:')}
203
222
  }
204
223
 
205
224
  case 'status': {
206
- requireArgs(args.slice(1), 1, 'lux flows status <id>');
207
- const flowId = args[1];
225
+ requireArgs(args.slice(1), 1, 'lux flows status <name-or-id>');
226
+ const flowId = resolveFlowId(args[1]);
208
227
 
209
228
  const flow = loadLocalFlow(flowId);
210
229
  if (!flow) {
211
- error(`Flow not found locally: ${flowId}`);
230
+ error(`Flow not found locally: ${args[1]}`);
212
231
  break;
213
232
  }
214
233
 
@@ -231,7 +250,7 @@ ${chalk.bold('Examples:')}
231
250
  conflict: chalk.red,
232
251
  };
233
252
 
234
- console.log(`\n📝 Flow: ${flow.name}`);
253
+ console.log(`\nFlow: ${flow.name}`);
235
254
  console.log(` ID: ${flowId}`);
236
255
  console.log(` Sync Status: ${statusColors[syncStatus](syncStatus)}`);
237
256
  console.log(` Local Version: ${flow.localVersion || 1}`);
@@ -243,10 +262,10 @@ ${chalk.bold('Examples:')}
243
262
  console.log(` Edges: ${flow.edges?.length || 0}`);
244
263
 
245
264
  if (syncStatus === 'conflict') {
246
- console.log(chalk.red('\n⚠️ This flow has conflicts with the cloud version.'));
265
+ console.log(chalk.red('\nThis flow has conflicts with the cloud version.'));
247
266
  console.log(chalk.gray(' Use the Lux Studio app to resolve conflicts.\n'));
248
267
  } else if (syncStatus === 'dirty') {
249
- console.log(chalk.yellow('\n📤 This flow has unpublished local changes.'));
268
+ console.log(chalk.yellow('\nThis flow has unpublished local changes.'));
250
269
  console.log(chalk.gray(' Run "lux flows publish ' + flowId + '" to publish.\n'));
251
270
  }
252
271
  break;
@@ -363,17 +382,17 @@ ${chalk.bold('Examples:')}
363
382
  }
364
383
 
365
384
  case 'delete': {
366
- requireArgs(args.slice(1), 1, 'lux flows delete <id>');
367
- const flowId = args[1];
385
+ requireArgs(args.slice(1), 1, 'lux flows delete <name-or-id>');
386
+ const flowId = resolveFlowId(args[1]);
368
387
 
369
388
  const flow = loadLocalFlow(flowId);
370
389
  if (!flow) {
371
- error(`Flow not found locally: ${flowId}`);
390
+ error(`Flow not found locally: ${args[1]}`);
372
391
  break;
373
392
  }
374
393
 
375
394
  if (flow.publishedVersion) {
376
- console.log(chalk.yellow(`\n⚠️ Warning: "${flow.name}" has been published.`));
395
+ console.log(chalk.yellow(`\nWarning: "${flow.name}" has been published.`));
377
396
  console.log(chalk.gray(' This only deletes the local copy. The published version remains in the cloud.\n'));
378
397
  }
379
398
 
@@ -383,8 +402,8 @@ ${chalk.bold('Examples:')}
383
402
  }
384
403
 
385
404
  case 'get': {
386
- requireArgs(args.slice(1), 1, 'lux flows get <id>');
387
- const flowId = args[1];
405
+ requireArgs(args.slice(1), 1, 'lux flows get <name-or-id>');
406
+ const flowId = resolveFlowId(args[1]);
388
407
 
389
408
  info(`Loading flow: ${flowId}`);
390
409
  const { data } = await axios.get(
@@ -398,14 +417,14 @@ ${chalk.bold('Examples:')}
398
417
 
399
418
  const workflow = data.workflow;
400
419
 
401
- console.log(`\n📝 Name: ${workflow.name}`);
402
- console.log(`📊 Status: ${workflow.status}`);
403
- console.log(`🔢 Version: ${workflow.version}`);
404
- console.log(`📅 Created: ${workflow.created_at}`);
405
- console.log(`📅 Updated: ${workflow.updated_at}`);
420
+ console.log(`\nName: ${workflow.name}`);
421
+ console.log(`Status: ${workflow.status}`);
422
+ console.log(`Version: ${workflow.version}`);
423
+ console.log(`Created: ${workflow.created_at}`);
424
+ console.log(`Updated: ${workflow.updated_at}`);
406
425
 
407
426
  if (workflow.config) {
408
- console.log(`\n📋 Current Config:\n`);
427
+ console.log(`\nCurrent Config:\n`);
409
428
  console.log(formatJson(workflow.config));
410
429
  }
411
430
 
@@ -540,14 +559,14 @@ ${chalk.bold('Examples:')}
540
559
  }
541
560
 
542
561
  case 'save': {
543
- requireArgs(args.slice(1), 2, 'lux flows save <id> <config-file>');
544
- const flowId = args[1];
562
+ requireArgs(args.slice(1), 2, 'lux flows save <name-or-id> <config-file>');
563
+ const flowId = resolveFlowId(args[1]);
545
564
  const configFile = args[2];
546
565
 
547
566
  // Load existing local flow
548
567
  const existingFlow = loadLocalFlow(flowId);
549
568
  if (!existingFlow) {
550
- error(`Flow not found locally: ${flowId}`);
569
+ error(`Flow not found locally: ${args[1]}`);
551
570
  console.log(chalk.gray('Run "lux flows sync" to sync from cloud first.'));
552
571
  break;
553
572
  }
@@ -586,13 +605,13 @@ ${chalk.bold('Examples:')}
586
605
  }
587
606
 
588
607
  case 'publish': {
589
- requireArgs(args.slice(1), 1, 'lux flows publish <id>');
590
- const flowId = args[1];
608
+ requireArgs(args.slice(1), 1, 'lux flows publish <name-or-id>');
609
+ const flowId = resolveFlowId(args[1]);
591
610
 
592
611
  // Load local flow
593
612
  const localFlow = loadLocalFlow(flowId);
594
613
  if (!localFlow) {
595
- error(`Flow not found locally: ${flowId}`);
614
+ error(`Flow not found locally: ${args[1]}`);
596
615
  console.log(chalk.gray('Run "lux flows sync" to sync from cloud first.'));
597
616
  break;
598
617
  }
@@ -657,13 +676,13 @@ ${chalk.bold('Examples:')}
657
676
  }
658
677
 
659
678
  case 'diff': {
660
- requireArgs(args.slice(1), 1, 'lux flows diff <id>');
661
- const flowId = args[1];
679
+ requireArgs(args.slice(1), 1, 'lux flows diff <name-or-id>');
680
+ const flowId = resolveFlowId(args[1]);
662
681
 
663
682
  // Load local flow
664
683
  const localFlow = loadLocalFlow(flowId);
665
684
  if (!localFlow) {
666
- error(`Flow not found locally: ${flowId}`);
685
+ error(`Flow not found locally: ${args[1]}`);
667
686
  break;
668
687
  }
669
688
 
@@ -676,7 +695,7 @@ ${chalk.bold('Examples:')}
676
695
 
677
696
  // Check if never published
678
697
  if (!localFlow.publishedVersion) {
679
- console.log('\n📝 NEW FLOW (not yet published)\n');
698
+ console.log('\nNEW FLOW (not yet published)\n');
680
699
  console.log(` Name: ${localFlow.name}`);
681
700
  console.log(` Local Version: ${localFlow.localVersion || 1}`);
682
701
  console.log(` Nodes: ${localConfig.nodes.length}`);
@@ -687,7 +706,7 @@ ${chalk.bold('Examples:')}
687
706
 
688
707
  // Check for conflicts
689
708
  if (localFlow.cloudData) {
690
- console.log('\n⚠️ CONFLICT DETECTED\n');
709
+ console.log('\nCONFLICT DETECTED\n');
691
710
  console.log('Local version:');
692
711
  console.log(` Version: ${localFlow.localVersion}`);
693
712
  console.log(` Nodes: ${localConfig.nodes.length}`);
@@ -708,7 +727,7 @@ ${chalk.bold('Examples:')}
708
727
  success('No changes - local matches published version');
709
728
  console.log(` Published Version: ${localFlow.publishedVersion}`);
710
729
  } else {
711
- console.log('\n📊 LOCAL CHANGES (unpublished)\n');
730
+ console.log('\nLOCAL CHANGES (unpublished)\n');
712
731
  console.log(` Local Version: ${localFlow.localVersion}`);
713
732
  console.log(` Published Version: ${localFlow.publishedVersion}`);
714
733
  console.log(` Nodes: ${localConfig.nodes.length}`);
@@ -719,26 +738,26 @@ ${chalk.bold('Examples:')}
719
738
  }
720
739
 
721
740
  case 'webhook-url': {
722
- requireArgs(args.slice(1), 1, 'lux flows webhook-url <flow-id>');
723
- const flowId = args[1];
741
+ requireArgs(args.slice(1), 1, 'lux flows webhook-url <name-or-id>');
742
+ const flowId = resolveFlowId(args[1]);
724
743
 
725
744
  info(`Getting webhook URL for: ${flowId}`);
726
745
  const tokenData = await getWebhookToken(flowId);
727
746
 
728
- console.log(`\n📍 Webhook URL:\n${tokenData.webhookUrl}\n`);
729
- console.log(`📊 Status:`);
730
- console.log(` Format Confirmed: ${tokenData.formatConfirmed ? 'Yes' : 'No'}`);
731
- console.log(` Webhook Trigger Enabled: ${tokenData.webhookTrigger ? 'Yes' : 'No'}\n`);
747
+ console.log(`\nWebhook URL:\n${tokenData.webhookUrl}\n`);
748
+ console.log(`Status:`);
749
+ console.log(` Format Confirmed: ${tokenData.formatConfirmed ? 'Yes' : 'No'}`);
750
+ console.log(` Webhook Trigger Enabled: ${tokenData.webhookTrigger ? 'Yes' : 'No'}\n`);
732
751
 
733
752
  if (!tokenData.formatConfirmed) {
734
- console.log(chalk.yellow('ℹ️ Run "lux flows webhook-listen" to capture a sample webhook'));
753
+ console.log(chalk.yellow('Run "lux flows webhook-listen" to capture a sample webhook'));
735
754
  }
736
755
  break;
737
756
  }
738
757
 
739
758
  case 'webhook-listen': {
740
- requireArgs(args.slice(1), 1, 'lux flows webhook-listen <flow-id>');
741
- const flowId = args[1];
759
+ requireArgs(args.slice(1), 1, 'lux flows webhook-listen <name-or-id>');
760
+ const flowId = resolveFlowId(args[1]);
742
761
 
743
762
  info(`Starting webhook listening session for: ${flowId}`);
744
763
  const tokenData = await getWebhookToken(flowId);
@@ -747,7 +766,7 @@ ${chalk.bold('Examples:')}
747
766
  await axios.post(`${WEBHOOK_WORKER_URL}/listening/start/${tokenData.token}`);
748
767
 
749
768
  success('Listening session started!');
750
- console.log(`\n📡 Now listening for webhooks at:\n${tokenData.webhookUrl}\n`);
769
+ console.log(`\nNow listening for webhooks at:\n${tokenData.webhookUrl}\n`);
751
770
  console.log('Session expires in 5 minutes.');
752
771
  console.log(`\nSend a webhook request to the URL above, then run:`);
753
772
  console.log(chalk.white(` lux flows webhook-poll ${flowId}\n`));
@@ -755,8 +774,8 @@ ${chalk.bold('Examples:')}
755
774
  }
756
775
 
757
776
  case 'webhook-poll': {
758
- requireArgs(args.slice(1), 1, 'lux flows webhook-poll <flow-id>');
759
- const flowId = args[1];
777
+ requireArgs(args.slice(1), 1, 'lux flows webhook-poll <name-or-id>');
778
+ const flowId = resolveFlowId(args[1]);
760
779
 
761
780
  const tokenData = await getWebhookToken(flowId);
762
781
  const pollData = await getCapturedPayload(tokenData.token);
@@ -767,8 +786,8 @@ ${chalk.bold('Examples:')}
767
786
  }
768
787
 
769
788
  case 'webhook-accept': {
770
- requireArgs(args.slice(1), 1, 'lux flows webhook-accept <flow-id>');
771
- const flowId = args[1];
789
+ requireArgs(args.slice(1), 1, 'lux flows webhook-accept <name-or-id>');
790
+ const flowId = resolveFlowId(args[1]);
772
791
 
773
792
  info(`Accepting webhook format for: ${flowId}`);
774
793
 
@@ -835,13 +854,13 @@ ${chalk.bold('Examples:')}
835
854
  }
836
855
 
837
856
  success('Webhook format updated!');
838
- console.log(`\n✅ Captured schema with ${Object.keys(schema).length} parameters`);
839
- console.log(`✅ Schema saved to database`);
857
+ console.log(`\nCaptured schema with ${Object.keys(schema).length} parameters`);
858
+ console.log(`Schema saved to database`);
840
859
  if (!alreadyConfirmed) {
841
- console.log(`✅ Worker accepted format`);
842
- console.log(`✅ Format confirmed`);
860
+ console.log(`Worker accepted format`);
861
+ console.log(`Format confirmed`);
843
862
  } else {
844
- console.log(`✅ Schema updated (already confirmed)`);
863
+ console.log(`Schema updated (already confirmed)`);
845
864
  }
846
865
  console.log('');
847
866
 
@@ -855,8 +874,8 @@ ${chalk.bold('Examples:')}
855
874
  }
856
875
 
857
876
  case 'webhook-decline': {
858
- requireArgs(args.slice(1), 1, 'lux flows webhook-decline <flow-id>');
859
- const flowId = args[1];
877
+ requireArgs(args.slice(1), 1, 'lux flows webhook-decline <name-or-id>');
878
+ const flowId = resolveFlowId(args[1]);
860
879
 
861
880
  info(`Declining webhook format for: ${flowId}`);
862
881
  const tokenData = await getWebhookToken(flowId);
@@ -872,8 +891,8 @@ ${chalk.bold('Examples:')}
872
891
  await axios.delete(`${WEBHOOK_WORKER_URL}/listening/decline/${tokenData.token}`);
873
892
 
874
893
  success('Webhook format declined!');
875
- console.log('\n✅ Schema cleared from database');
876
- console.log('Listening session has been reset');
894
+ console.log('\nSchema cleared from database');
895
+ console.log('Listening session has been reset');
877
896
  console.log(`\nRun "lux flows webhook-listen ${flowId}" to try again.\n`);
878
897
  break;
879
898
  }
@@ -881,8 +900,8 @@ ${chalk.bold('Examples:')}
881
900
  // ============ EXECUTION HISTORY COMMANDS ============
882
901
 
883
902
  case 'executions': {
884
- requireArgs(args.slice(1), 1, 'lux flows executions <flow-id> [--limit N]');
885
- const flowId = args[1];
903
+ requireArgs(args.slice(1), 1, 'lux flows executions <name-or-id> [--limit N]');
904
+ const flowId = resolveFlowId(args[1]);
886
905
 
887
906
  // Parse --limit flag
888
907
  const limitIndex = args.indexOf('--limit');
@@ -924,7 +943,7 @@ ${chalk.bold('Examples:')}
924
943
  const flow = loadLocalFlow(flowId);
925
944
  const flowName = flow?.name || flowId;
926
945
 
927
- console.log(`\n📊 Execution History for "${flowName}" (${executions.length})\n`);
946
+ console.log(`\nExecution History for "${flowName}" (${executions.length})\n`);
928
947
 
929
948
  // Status colors
930
949
  const statusColors = {
@@ -963,8 +982,8 @@ ${chalk.bold('Examples:')}
963
982
  }
964
983
 
965
984
  case 'execution': {
966
- requireArgs(args.slice(1), 2, 'lux flows execution <flow-id> <execution-id>');
967
- const flowId = args[1];
985
+ requireArgs(args.slice(1), 2, 'lux flows execution <name-or-id> <execution-id>');
986
+ const flowId = resolveFlowId(args[1]);
968
987
  const executionId = args[2];
969
988
  const jsonOutput = args.includes('--json');
970
989
 
@@ -1009,7 +1028,7 @@ ${chalk.bold('Examples:')}
1009
1028
  };
1010
1029
  const statusColor = statusColors[exec.status] || chalk.white;
1011
1030
 
1012
- console.log(`\n📋 Execution Details\n`);
1031
+ console.log(`\nExecution Details\n`);
1013
1032
  console.log(` ID: ${exec.id}`);
1014
1033
  console.log(` Flow: ${flowName}`);
1015
1034
  console.log(` Status: ${statusColor(exec.status)}`);
@@ -1021,28 +1040,28 @@ ${chalk.bold('Examples:')}
1021
1040
  console.log(` Test Run: ${exec.isTest ? chalk.yellow('Yes') : 'No'}`);
1022
1041
 
1023
1042
  if (exec.error) {
1024
- console.log(`\n${chalk.red('Error:')}`);
1043
+ console.log(`\n${chalk.red('Error:')}`);
1025
1044
  console.log(` ${exec.error}`);
1026
1045
  }
1027
1046
 
1028
1047
  // Show input data
1029
1048
  if (exec.inputData && Object.keys(exec.inputData).length > 0) {
1030
- console.log(`\n${chalk.cyan('📥 Input Data:')}`);
1049
+ console.log(`\n${chalk.cyan('Input Data:')}`);
1031
1050
  console.log(formatJson(exec.inputData));
1032
1051
  }
1033
1052
 
1034
1053
  // Show output data
1035
1054
  if (exec.outputData && Object.keys(exec.outputData).length > 0) {
1036
- console.log(`\n${chalk.cyan('📤 Output Data:')}`);
1055
+ console.log(`\n${chalk.cyan('Output Data:')}`);
1037
1056
  console.log(formatJson(exec.outputData));
1038
1057
  } else if (exec.output) {
1039
- console.log(`\n${chalk.cyan('📤 Output:')}`);
1058
+ console.log(`\n${chalk.cyan('Output:')}`);
1040
1059
  console.log(formatJson(exec.output));
1041
1060
  }
1042
1061
 
1043
1062
  // Show node executions summary
1044
1063
  if (exec.nodeExecutions && exec.nodeExecutions.length > 0) {
1045
- console.log(`\n${chalk.cyan('🔗 Node Executions:')} (${exec.nodeExecutions.length} nodes)\n`);
1064
+ console.log(`\n${chalk.cyan('Node Executions:')} (${exec.nodeExecutions.length} nodes)\n`);
1046
1065
 
1047
1066
  const nodeFormatted = exec.nodeExecutions.map((node) => {
1048
1067
  const nodeStatus = node.status || 'unknown';
@@ -1054,7 +1073,7 @@ ${chalk.bold('Examples:')}
1054
1073
  type: node.nodeType || '-',
1055
1074
  status: nodeStatusColor(nodeStatus),
1056
1075
  duration: nodeDuration,
1057
- error: node.error ? chalk.red('') : '',
1076
+ error: node.error ? chalk.red('err') : '',
1058
1077
  };
1059
1078
  });
1060
1079
 
@@ -1067,8 +1086,8 @@ ${chalk.bold('Examples:')}
1067
1086
  }
1068
1087
 
1069
1088
  case 'node': {
1070
- requireArgs(args.slice(1), 3, 'lux flows node <flow-id> <execution-id> <node-id>');
1071
- const flowId = args[1];
1089
+ requireArgs(args.slice(1), 3, 'lux flows node <name-or-id> <execution-id> <node-id>');
1090
+ const flowId = resolveFlowId(args[1]);
1072
1091
  const executionId = args[2];
1073
1092
  const nodeId = args[3];
1074
1093
  const jsonOutput = args.includes('--json');
@@ -1124,7 +1143,7 @@ ${chalk.bold('Examples:')}
1124
1143
  };
1125
1144
  const statusColor = statusColors[nodeExec.status] || chalk.white;
1126
1145
 
1127
- console.log(`\n🔗 Node Execution Details\n`);
1146
+ console.log(`\nNode Execution Details\n`);
1128
1147
  console.log(` Node ID: ${nodeExec.nodeId || nodeExec.id}`);
1129
1148
  console.log(` Type: ${nodeExec.nodeType || '-'}`);
1130
1149
  console.log(` Label: ${nodeExec.label || '-'}`);
@@ -1134,31 +1153,31 @@ ${chalk.bold('Examples:')}
1134
1153
  console.log(` Completed: ${nodeExec.completedAt ? new Date(nodeExec.completedAt).toLocaleString() : '-'}`);
1135
1154
 
1136
1155
  if (nodeExec.error) {
1137
- console.log(`\n${chalk.red('Error:')}`);
1156
+ console.log(`\n${chalk.red('Error:')}`);
1138
1157
  console.log(` ${nodeExec.error}`);
1139
1158
  }
1140
1159
 
1141
1160
  // Show node config
1142
1161
  if (nodeExec.config && Object.keys(nodeExec.config).length > 0) {
1143
- console.log(`\n${chalk.cyan('⚙️ Node Config:')}`);
1162
+ console.log(`\n${chalk.cyan('Node Config:')}`);
1144
1163
  console.log(formatJson(nodeExec.config));
1145
1164
  }
1146
1165
 
1147
1166
  // Show input
1148
1167
  if (nodeExec.input !== undefined) {
1149
- console.log(`\n${chalk.cyan('📥 Input:')}`);
1168
+ console.log(`\n${chalk.cyan('Input:')}`);
1150
1169
  console.log(formatJson(nodeExec.input));
1151
1170
  }
1152
1171
 
1153
1172
  // Show output
1154
1173
  if (nodeExec.output !== undefined) {
1155
- console.log(`\n${chalk.cyan('📤 Output:')}`);
1174
+ console.log(`\n${chalk.cyan('Output:')}`);
1156
1175
  console.log(formatJson(nodeExec.output));
1157
1176
  }
1158
1177
 
1159
1178
  // Show raw data if nothing else
1160
1179
  if (!nodeExec.input && !nodeExec.output && !nodeExec.config) {
1161
- console.log(`\n${chalk.cyan('📋 Raw Node Data:')}`);
1180
+ console.log(`\n${chalk.cyan('Raw Node Data:')}`);
1162
1181
  console.log(formatJson(nodeExec));
1163
1182
  }
1164
1183
 
@@ -1167,8 +1186,8 @@ ${chalk.bold('Examples:')}
1167
1186
  }
1168
1187
 
1169
1188
  case 'last': {
1170
- requireArgs(args.slice(1), 1, 'lux flows last <flow-id>');
1171
- const flowId = args[1];
1189
+ requireArgs(args.slice(1), 1, 'lux flows last <name-or-id>');
1190
+ const flowId = resolveFlowId(args[1]);
1172
1191
  const jsonOutput = args.includes('--json');
1173
1192
 
1174
1193
  const projectId = getProjectId();
@@ -1217,9 +1236,9 @@ ${chalk.bold('Examples:')}
1217
1236
  const flow = loadLocalFlow(flowId);
1218
1237
  const flowName = flow?.name || flowId;
1219
1238
 
1220
- const status = exec.status === 'completed' ? chalk.green('Success') :
1221
- exec.status === 'failed' ? chalk.red('Failed') :
1222
- chalk.yellow('⏳ ' + exec.status);
1239
+ const status = exec.status === 'completed' ? chalk.green('Success') :
1240
+ exec.status === 'failed' ? chalk.red('Failed') :
1241
+ chalk.yellow(exec.status);
1223
1242
  const timestamp = new Date(exec.startedAt).toLocaleString();
1224
1243
  const duration = exec.duration ? `${(exec.duration / 1000).toFixed(1)}s` : '-';
1225
1244
 
@@ -1232,9 +1251,9 @@ ${chalk.bold('Examples:')}
1232
1251
  if (exec.nodeExecutions && exec.nodeExecutions.length > 0) {
1233
1252
  console.log(`\n Node Results:`);
1234
1253
  exec.nodeExecutions.forEach((node, i) => {
1235
- const nodeStatus = node.status === 'completed' ? chalk.green('') :
1236
- node.status === 'failed' ? chalk.red('') :
1237
- chalk.yellow('');
1254
+ const nodeStatus = node.status === 'completed' ? chalk.green('ok') :
1255
+ node.status === 'failed' ? chalk.red('fail') :
1256
+ chalk.yellow('...');
1238
1257
  const nodeDuration = node.duration ? `${node.duration}ms` : '-';
1239
1258
  let outputPreview = '';
1240
1259
  if (node.output) {
@@ -1263,8 +1282,8 @@ ${chalk.bold('Examples:')}
1263
1282
  }
1264
1283
 
1265
1284
  case 'test': {
1266
- requireArgs(args.slice(1), 1, 'lux flows test <flow-id> [--data <json>] [--data-file <path>]');
1267
- const flowId = args[1];
1285
+ requireArgs(args.slice(1), 1, 'lux flows test <name-or-id> [--data <json>] [--data-file <path>]');
1286
+ const flowId = resolveFlowId(args[1]);
1268
1287
  const jsonOutput = args.includes('--json');
1269
1288
 
1270
1289
  // Parse --data or --data-file arguments
@@ -1288,7 +1307,7 @@ ${chalk.bold('Examples:')}
1288
1307
  // Load flow from local storage
1289
1308
  const flowData = loadLocalFlow(flowId);
1290
1309
  if (!flowData) {
1291
- error(`Flow not found locally: ${flowId}`);
1310
+ error(`Flow not found locally: ${args[1]}`);
1292
1311
  console.log(chalk.gray('Run "lux flows sync" to sync from cloud first.'));
1293
1312
  break;
1294
1313
  }
@@ -1329,9 +1348,9 @@ ${chalk.bold('Examples:')}
1329
1348
 
1330
1349
  if (result.nodeExecutions && result.nodeExecutions.length > 0) {
1331
1350
  result.nodeExecutions.forEach((node) => {
1332
- const nodeStatus = node.status === 'completed' ? chalk.green('') :
1333
- node.status === 'failed' ? chalk.red('') :
1334
- chalk.yellow('');
1351
+ const nodeStatus = node.status === 'completed' ? chalk.green('ok') :
1352
+ node.status === 'failed' ? chalk.red('fail') :
1353
+ chalk.yellow('...');
1335
1354
  const nodeDuration = node.duration ? `${node.duration}ms` : '-';
1336
1355
  let outputPreview = '';
1337
1356
  if (node.output) {