lua-cli 2.5.7 → 3.0.0-alpha.1

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 (124) hide show
  1. package/dist/api/agent.api.service.d.ts +45 -0
  2. package/dist/api/agent.api.service.js +54 -0
  3. package/dist/api/job.api.service.d.ts +210 -0
  4. package/dist/api/job.api.service.js +200 -0
  5. package/dist/api/lazy-instances.d.ts +24 -0
  6. package/dist/api/lazy-instances.js +48 -0
  7. package/dist/api/postprocessor.api.service.d.ts +98 -0
  8. package/dist/api/postprocessor.api.service.js +76 -0
  9. package/dist/api/preprocessor.api.service.d.ts +98 -0
  10. package/dist/api/preprocessor.api.service.js +76 -0
  11. package/dist/api/user.data.api.service.d.ts +28 -0
  12. package/dist/api/user.data.api.service.js +51 -0
  13. package/dist/api/webhook.api.service.d.ts +151 -0
  14. package/dist/api/webhook.api.service.js +134 -0
  15. package/dist/api-exports.d.ts +156 -41
  16. package/dist/api-exports.js +182 -21
  17. package/dist/cli/command-definitions.js +149 -7
  18. package/dist/commands/compile.js +124 -5
  19. package/dist/commands/completion.d.ts +11 -0
  20. package/dist/commands/completion.js +209 -0
  21. package/dist/commands/env.d.ts +3 -2
  22. package/dist/commands/env.js +42 -17
  23. package/dist/commands/features.d.ts +16 -0
  24. package/dist/commands/features.js +352 -0
  25. package/dist/commands/index.d.ts +7 -0
  26. package/dist/commands/index.js +7 -0
  27. package/dist/commands/init.js +53 -7
  28. package/dist/commands/jobs.d.ts +20 -0
  29. package/dist/commands/jobs.js +533 -0
  30. package/dist/commands/logs.js +2 -5
  31. package/dist/commands/persona.d.ts +3 -2
  32. package/dist/commands/persona.js +43 -18
  33. package/dist/commands/postprocessors.d.ts +8 -0
  34. package/dist/commands/postprocessors.js +431 -0
  35. package/dist/commands/preprocessors.d.ts +8 -0
  36. package/dist/commands/preprocessors.js +431 -0
  37. package/dist/commands/push.d.ts +9 -13
  38. package/dist/commands/push.js +937 -69
  39. package/dist/commands/skills.d.ts +16 -0
  40. package/dist/commands/skills.js +438 -0
  41. package/dist/commands/test.d.ts +9 -18
  42. package/dist/commands/test.js +558 -82
  43. package/dist/commands/webhooks.d.ts +18 -0
  44. package/dist/commands/webhooks.js +424 -0
  45. package/dist/common/data.entry.instance.d.ts +7 -0
  46. package/dist/common/data.entry.instance.js +15 -0
  47. package/dist/common/job.instance.d.ts +77 -0
  48. package/dist/common/job.instance.js +108 -0
  49. package/dist/common/order.instance.d.ts +6 -0
  50. package/dist/common/order.instance.js +14 -0
  51. package/dist/common/product.instance.d.ts +6 -0
  52. package/dist/common/product.instance.js +14 -0
  53. package/dist/common/user.instance.d.ts +15 -0
  54. package/dist/common/user.instance.js +38 -0
  55. package/dist/config/constants.d.ts +2 -2
  56. package/dist/config/constants.js +4 -4
  57. package/dist/index.js +14 -3
  58. package/dist/interfaces/agent.d.ts +33 -1
  59. package/dist/interfaces/chat.d.ts +22 -0
  60. package/dist/interfaces/index.d.ts +10 -0
  61. package/dist/interfaces/index.js +7 -0
  62. package/dist/interfaces/jobs.d.ts +172 -0
  63. package/dist/interfaces/jobs.js +5 -0
  64. package/dist/interfaces/message.d.ts +18 -0
  65. package/dist/interfaces/message.js +1 -0
  66. package/dist/interfaces/postprocessors.d.ts +35 -0
  67. package/dist/interfaces/postprocessors.js +4 -0
  68. package/dist/interfaces/preprocessors.d.ts +35 -0
  69. package/dist/interfaces/preprocessors.js +4 -0
  70. package/dist/interfaces/webhooks.d.ts +104 -0
  71. package/dist/interfaces/webhooks.js +5 -0
  72. package/dist/types/api-contracts.d.ts +14 -0
  73. package/dist/types/api-contracts.js +0 -7
  74. package/dist/types/compile.types.d.ts +49 -0
  75. package/dist/types/index.d.ts +1 -1
  76. package/dist/types/index.js +1 -1
  77. package/dist/types/skill.d.ts +502 -0
  78. package/dist/types/skill.js +477 -0
  79. package/dist/utils/agent-management.d.ts +25 -0
  80. package/dist/utils/agent-management.js +67 -0
  81. package/dist/utils/bundling.d.ts +31 -1
  82. package/dist/utils/bundling.js +653 -10
  83. package/dist/utils/compile.d.ts +63 -0
  84. package/dist/utils/compile.js +691 -36
  85. package/dist/utils/deployment.d.ts +2 -1
  86. package/dist/utils/deployment.js +16 -2
  87. package/dist/utils/init-agent.d.ts +3 -1
  88. package/dist/utils/init-agent.js +6 -4
  89. package/dist/utils/init-prompts.d.ts +2 -1
  90. package/dist/utils/init-prompts.js +14 -9
  91. package/dist/utils/job-management.d.ts +24 -0
  92. package/dist/utils/job-management.js +264 -0
  93. package/dist/utils/postprocessor-management.d.ts +9 -0
  94. package/dist/utils/postprocessor-management.js +118 -0
  95. package/dist/utils/preprocessor-management.d.ts +9 -0
  96. package/dist/utils/preprocessor-management.js +118 -0
  97. package/dist/utils/sandbox.d.ts +61 -1
  98. package/dist/utils/sandbox.js +283 -72
  99. package/dist/utils/tool-detection.d.ts +3 -2
  100. package/dist/utils/tool-detection.js +18 -4
  101. package/dist/utils/webhook-management.d.ts +24 -0
  102. package/dist/utils/webhook-management.js +256 -0
  103. package/dist/web/app.css +152 -736
  104. package/dist/web/app.js +45 -45
  105. package/package.json +2 -2
  106. package/template/AGENT_CONFIGURATION.md +251 -0
  107. package/template/COMPLEX_JOB_EXAMPLES.md +795 -0
  108. package/template/DYNAMIC_JOB_CREATION.md +371 -0
  109. package/template/README.md +30 -2
  110. package/template/WEBHOOKS_JOBS_QUICKSTART.md +318 -0
  111. package/template/WEBHOOK_JOB_EXAMPLES.md +817 -0
  112. package/template/package.json +1 -1
  113. package/template/src/index-agent-example.ts +201 -0
  114. package/template/src/index.ts +39 -0
  115. package/template/src/jobs/AbandonedBasketProcessorJob.ts +139 -0
  116. package/template/src/jobs/DailyCleanupJob.ts +100 -0
  117. package/template/src/jobs/DataMigrationJob.ts +133 -0
  118. package/template/src/jobs/HealthCheckJob.ts +87 -0
  119. package/template/src/postprocessors/ResponseFormatter.ts +151 -0
  120. package/template/src/preprocessors/MessageFilter.ts +91 -0
  121. package/template/src/tools/GameScoreTrackerTool.ts +356 -0
  122. package/template/src/tools/SmartBasketTool.ts +188 -0
  123. package/template/src/webhooks/PaymentWebhook.ts +113 -0
  124. package/template/src/webhooks/UserEventWebhook.ts +77 -0
@@ -115,8 +115,8 @@ export function extractToolFromNewExpressionSync(newExpr, project) {
115
115
  try {
116
116
  const expression = newExpr.getExpression();
117
117
  const className = expression.getText();
118
- // Find the import declaration for this class
119
118
  const sourceFile = newExpr.getSourceFile();
119
+ // Strategy 1: Try to find the tool via imports (separate file)
120
120
  const imports = sourceFile.getImportDeclarations();
121
121
  for (const importDecl of imports) {
122
122
  const namedImports = importDecl.getNamedImports();
@@ -134,43 +134,20 @@ export function extractToolFromNewExpressionSync(newExpr, project) {
134
134
  toolFilePath = resolveImportPath(importDecl.getModuleSpecifierValue(), sourceFile.getFilePath());
135
135
  }
136
136
  if (toolFilePath && fs.existsSync(toolFilePath)) {
137
- // Extract tool metadata from the class file
138
- try {
139
- const toolSourceFile = project.addSourceFileAtPath(toolFilePath);
140
- const classDecl = toolSourceFile.getClass(className);
141
- if (classDecl) {
142
- const nameProperty = classDecl.getProperty('name');
143
- const descProperty = classDecl.getProperty('description');
144
- let toolName = className.replace(/Tool$/, '').toLowerCase();
145
- let description = '';
146
- // Extract name from property if available
147
- if (nameProperty && nameProperty.getInitializer()) {
148
- const nameValue = nameProperty.getInitializer()?.getText();
149
- if (nameValue) {
150
- toolName = nameValue.replace(/['"]/g, '');
151
- }
152
- }
153
- // Extract description from property if available
154
- if (descProperty && descProperty.getInitializer()) {
155
- const descValue = descProperty.getInitializer()?.getText();
156
- if (descValue) {
157
- description = descValue.replace(/['"]/g, '');
158
- }
159
- }
160
- const toolInfo = {
161
- name: toolName,
162
- className,
163
- filePath: toolFilePath,
164
- description
165
- };
166
- return toolInfo;
167
- }
168
- }
169
- catch (fileError) {
170
- console.warn(`Warning: Could not load tool file ${toolFilePath}:`, fileError);
171
- }
137
+ // Extract tool metadata from the separate file
138
+ const toolInfo = extractToolMetadataFromFile(toolFilePath, className, project);
139
+ if (toolInfo)
140
+ return toolInfo;
172
141
  }
173
142
  }
143
+ // Strategy 2: Check if tool is defined inline in the same file
144
+ const classDecl = sourceFile.getClass(className);
145
+ if (classDecl) {
146
+ // Tool is defined inline - extract metadata directly
147
+ const toolInfo = extractToolMetadataFromClass(classDecl, className, sourceFile.getFilePath());
148
+ if (toolInfo)
149
+ return toolInfo;
150
+ }
174
151
  return null;
175
152
  }
176
153
  catch (error) {
@@ -178,6 +155,51 @@ export function extractToolFromNewExpressionSync(newExpr, project) {
178
155
  return null;
179
156
  }
180
157
  }
158
+ /**
159
+ * Extracts tool metadata from a separate tool file.
160
+ */
161
+ function extractToolMetadataFromFile(toolFilePath, className, project) {
162
+ try {
163
+ const toolSourceFile = project.addSourceFileAtPath(toolFilePath);
164
+ const classDecl = toolSourceFile.getClass(className);
165
+ if (classDecl) {
166
+ return extractToolMetadataFromClass(classDecl, className, toolFilePath);
167
+ }
168
+ }
169
+ catch (fileError) {
170
+ console.warn(`Warning: Could not load tool file ${toolFilePath}:`, fileError);
171
+ }
172
+ return null;
173
+ }
174
+ /**
175
+ * Extracts tool metadata from a class declaration (works for both inline and separate files).
176
+ */
177
+ function extractToolMetadataFromClass(classDecl, className, filePath) {
178
+ const nameProperty = classDecl.getProperty('name');
179
+ const descProperty = classDecl.getProperty('description');
180
+ let toolName = className.replace(/Tool$/, '').toLowerCase();
181
+ let description = '';
182
+ // Extract name from property if available
183
+ if (nameProperty && nameProperty.getInitializer()) {
184
+ const nameValue = nameProperty.getInitializer()?.getText();
185
+ if (nameValue) {
186
+ toolName = nameValue.replace(/['"]/g, '');
187
+ }
188
+ }
189
+ // Extract description from property if available
190
+ if (descProperty && descProperty.getInitializer()) {
191
+ const descValue = descProperty.getInitializer()?.getText();
192
+ if (descValue) {
193
+ description = descValue.replace(/['"]/g, '');
194
+ }
195
+ }
196
+ return {
197
+ name: toolName,
198
+ className,
199
+ filePath,
200
+ description
201
+ };
202
+ }
181
203
  /**
182
204
  * Extracts skills metadata from index file
183
205
  */
@@ -240,3 +262,636 @@ export function extractSkillsMetadata(indexFile) {
240
262
  });
241
263
  return skills;
242
264
  }
265
+ /**
266
+ * Extracts webhooks metadata from index file
267
+ */
268
+ export function extractWebhooksMetadata(indexFile) {
269
+ const webhooks = [];
270
+ // Find all LuaWebhook constructor calls
271
+ indexFile.forEachDescendant((node) => {
272
+ if (Node.isNewExpression(node)) {
273
+ const expression = node.getExpression();
274
+ if (expression.getText() === 'LuaWebhook') {
275
+ const args = node.getArguments();
276
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
277
+ const configObj = args[0];
278
+ let webhookName = '';
279
+ let webhookVersion = '';
280
+ let description = '';
281
+ let context = '';
282
+ // Extract properties
283
+ configObj.getProperties().forEach((prop) => {
284
+ if (Node.isPropertyAssignment(prop)) {
285
+ const name = prop.getName();
286
+ const value = prop.getInitializer();
287
+ if (name === 'name' && value) {
288
+ webhookName = value.getText().replace(/['"]/g, '');
289
+ }
290
+ else if (name === 'version' && value) {
291
+ webhookVersion = value.getText().replace(/['"]/g, '');
292
+ }
293
+ else if (name === 'description' && value) {
294
+ description = value.getText().replace(/['"]/g, '');
295
+ }
296
+ else if (name === 'context' && value) {
297
+ context = value.getText().replace(/['"]/g, '');
298
+ }
299
+ }
300
+ });
301
+ if (webhookName) {
302
+ webhooks.push({
303
+ name: webhookName,
304
+ version: webhookVersion || '1.0.0',
305
+ description,
306
+ context
307
+ });
308
+ }
309
+ }
310
+ }
311
+ }
312
+ });
313
+ return webhooks;
314
+ }
315
+ /**
316
+ * Extracts jobs metadata from index file
317
+ */
318
+ export function extractJobsMetadata(indexFile) {
319
+ const jobs = [];
320
+ // Find all LuaJob constructor calls
321
+ indexFile.forEachDescendant((node) => {
322
+ if (Node.isNewExpression(node)) {
323
+ const expression = node.getExpression();
324
+ if (expression.getText() === 'LuaJob') {
325
+ const args = node.getArguments();
326
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
327
+ const configObj = args[0];
328
+ let jobName = '';
329
+ let jobVersion = '';
330
+ let description = '';
331
+ let context = '';
332
+ let schedule = null;
333
+ let timeout;
334
+ let retry = undefined;
335
+ let metadata = undefined;
336
+ // Extract properties
337
+ configObj.getProperties().forEach((prop) => {
338
+ if (Node.isPropertyAssignment(prop)) {
339
+ const name = prop.getName();
340
+ const value = prop.getInitializer();
341
+ if (name === 'name' && value) {
342
+ jobName = value.getText().replace(/['"]/g, '');
343
+ }
344
+ else if (name === 'version' && value) {
345
+ jobVersion = value.getText().replace(/['"]/g, '');
346
+ }
347
+ else if (name === 'description' && value) {
348
+ description = value.getText().replace(/['"]/g, '');
349
+ }
350
+ else if (name === 'context' && value) {
351
+ context = value.getText().replace(/['"]/g, '');
352
+ }
353
+ else if (name === 'schedule' && value) {
354
+ // Extract schedule configuration
355
+ try {
356
+ const scheduleText = value.getText();
357
+ // Try to evaluate the schedule object
358
+ schedule = eval(`(${scheduleText})`);
359
+ }
360
+ catch (error) {
361
+ console.warn('Warning: Could not parse schedule:', error);
362
+ schedule = { type: 'unknown' };
363
+ }
364
+ }
365
+ else if (name === 'timeout' && value) {
366
+ const timeoutText = value.getText();
367
+ timeout = parseInt(timeoutText, 10);
368
+ }
369
+ else if (name === 'retry' && value) {
370
+ // Extract retry configuration
371
+ try {
372
+ const retryText = value.getText();
373
+ retry = eval(`(${retryText})`);
374
+ }
375
+ catch (error) {
376
+ console.warn('Warning: Could not parse retry config:', error);
377
+ }
378
+ }
379
+ else if (name === 'metadata' && value) {
380
+ // Extract metadata
381
+ try {
382
+ const metadataText = value.getText();
383
+ metadata = eval(`(${metadataText})`);
384
+ }
385
+ catch (error) {
386
+ console.warn('Warning: Could not parse metadata:', error);
387
+ }
388
+ }
389
+ }
390
+ });
391
+ if (jobName) {
392
+ jobs.push({
393
+ name: jobName,
394
+ version: jobVersion || '1.0.0',
395
+ description,
396
+ context,
397
+ schedule,
398
+ timeout,
399
+ retry,
400
+ metadata
401
+ });
402
+ }
403
+ }
404
+ }
405
+ }
406
+ });
407
+ return jobs;
408
+ }
409
+ /**
410
+ * Extracts preprocessors metadata from index file
411
+ */
412
+ export function extractPreProcessorsMetadata(indexFile) {
413
+ const preprocessors = [];
414
+ // Find all PreProcessor constructor calls
415
+ indexFile.forEachDescendant((node) => {
416
+ if (Node.isNewExpression(node)) {
417
+ const expression = node.getExpression();
418
+ if (expression.getText() === 'PreProcessor') {
419
+ const args = node.getArguments();
420
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
421
+ const configObj = args[0];
422
+ let name = '';
423
+ let version = '';
424
+ let description = '';
425
+ let context = '';
426
+ configObj.getProperties().forEach((prop) => {
427
+ if (Node.isPropertyAssignment(prop)) {
428
+ const propName = prop.getName();
429
+ const value = prop.getInitializer();
430
+ if (propName === 'name' && value) {
431
+ name = value.getText().replace(/['"]/g, '');
432
+ }
433
+ else if (propName === 'version' && value) {
434
+ version = value.getText().replace(/['"]/g, '');
435
+ }
436
+ else if (propName === 'description' && value) {
437
+ description = value.getText().replace(/['"]/g, '');
438
+ }
439
+ else if (propName === 'context' && value) {
440
+ context = value.getText().replace(/['"]/g, '');
441
+ }
442
+ }
443
+ });
444
+ if (name) {
445
+ preprocessors.push({
446
+ name,
447
+ version: version || '1.0.0',
448
+ description,
449
+ context
450
+ });
451
+ }
452
+ }
453
+ }
454
+ }
455
+ });
456
+ return preprocessors;
457
+ }
458
+ /**
459
+ * Extracts postprocessors metadata from index file
460
+ */
461
+ export function extractPostProcessorsMetadata(indexFile) {
462
+ const postprocessors = [];
463
+ // Find all PostProcessor constructor calls
464
+ indexFile.forEachDescendant((node) => {
465
+ if (Node.isNewExpression(node)) {
466
+ const expression = node.getExpression();
467
+ if (expression.getText() === 'PostProcessor') {
468
+ const args = node.getArguments();
469
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
470
+ const configObj = args[0];
471
+ let name = '';
472
+ let version = '';
473
+ let description = '';
474
+ let context = '';
475
+ configObj.getProperties().forEach((prop) => {
476
+ if (Node.isPropertyAssignment(prop)) {
477
+ const propName = prop.getName();
478
+ const value = prop.getInitializer();
479
+ if (propName === 'name' && value) {
480
+ name = value.getText().replace(/['"]/g, '');
481
+ }
482
+ else if (propName === 'version' && value) {
483
+ version = value.getText().replace(/['"]/g, '');
484
+ }
485
+ else if (propName === 'description' && value) {
486
+ description = value.getText().replace(/['"]/g, '');
487
+ }
488
+ else if (propName === 'context' && value) {
489
+ context = value.getText().replace(/['"]/g, '');
490
+ }
491
+ }
492
+ });
493
+ if (name) {
494
+ postprocessors.push({
495
+ name,
496
+ version: version || '1.0.0',
497
+ description,
498
+ context
499
+ });
500
+ }
501
+ }
502
+ }
503
+ }
504
+ });
505
+ return postprocessors;
506
+ }
507
+ /**
508
+ * Extracts LuaAgent metadata from index file.
509
+ * Returns the unified agent configuration if found, otherwise null.
510
+ * This function looks for either:
511
+ * - A LuaAgent constructor call: new LuaAgent({ ... })
512
+ * - A variable assigned to LuaAgent: const agent = new LuaAgent({ ... })
513
+ */
514
+ export function extractLuaAgentMetadata(indexFile) {
515
+ let agentMetadata = null;
516
+ // Find LuaAgent constructor calls
517
+ indexFile.forEachDescendant((node) => {
518
+ if (Node.isNewExpression(node)) {
519
+ const expression = node.getExpression();
520
+ if (expression.getText() === 'LuaAgent') {
521
+ const args = node.getArguments();
522
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
523
+ const configObj = args[0];
524
+ let name = '';
525
+ let persona = '';
526
+ let welcomeMessage = '';
527
+ const skills = [];
528
+ const webhooks = [];
529
+ const jobs = [];
530
+ const preProcessors = [];
531
+ const postProcessors = [];
532
+ // Extract properties from LuaAgent config
533
+ configObj.getProperties().forEach((prop) => {
534
+ if (Node.isPropertyAssignment(prop)) {
535
+ const propName = prop.getName();
536
+ const value = prop.getInitializer();
537
+ if (propName === 'name' && value) {
538
+ name = value.getText().replace(/['"]/g, '');
539
+ }
540
+ else if (propName === 'persona' && value) {
541
+ // Handle multi-line strings and template literals
542
+ const personaText = value.getText();
543
+ persona = personaText
544
+ .replace(/^['"`]/, '')
545
+ .replace(/['"`]$/, '')
546
+ .replace(/\\n/g, '\n')
547
+ .trim();
548
+ }
549
+ else if (propName === 'welcomeMessage' && value) {
550
+ welcomeMessage = value.getText().replace(/['"]/g, '');
551
+ }
552
+ else if (propName === 'skills' && value && Node.isArrayLiteralExpression(value)) {
553
+ // Extract skill references from the array
554
+ value.getElements().forEach((element) => {
555
+ // Skills can be variable references or inline new LuaSkill()
556
+ if (Node.isIdentifier(element)) {
557
+ skills.push({ ref: element.getText() });
558
+ }
559
+ else if (Node.isNewExpression(element)) {
560
+ // Extract inline skill metadata
561
+ const skillArgs = element.getArguments();
562
+ if (skillArgs.length > 0 && Node.isObjectLiteralExpression(skillArgs[0])) {
563
+ const skillConfig = extractConfigFromObjectLiteral(skillArgs[0]);
564
+ skills.push(skillConfig);
565
+ }
566
+ }
567
+ });
568
+ }
569
+ else if (propName === 'webhooks' && value && Node.isArrayLiteralExpression(value)) {
570
+ value.getElements().forEach((element) => {
571
+ if (Node.isIdentifier(element)) {
572
+ webhooks.push({ ref: element.getText() });
573
+ }
574
+ else if (Node.isNewExpression(element)) {
575
+ const webhookArgs = element.getArguments();
576
+ if (webhookArgs.length > 0 && Node.isObjectLiteralExpression(webhookArgs[0])) {
577
+ const webhookConfig = extractConfigFromObjectLiteral(webhookArgs[0]);
578
+ webhooks.push(webhookConfig);
579
+ }
580
+ }
581
+ });
582
+ }
583
+ else if (propName === 'jobs' && value && Node.isArrayLiteralExpression(value)) {
584
+ value.getElements().forEach((element) => {
585
+ if (Node.isIdentifier(element)) {
586
+ jobs.push({ ref: element.getText() });
587
+ }
588
+ else if (Node.isNewExpression(element)) {
589
+ const jobArgs = element.getArguments();
590
+ if (jobArgs.length > 0 && Node.isObjectLiteralExpression(jobArgs[0])) {
591
+ const jobConfig = extractConfigFromObjectLiteral(jobArgs[0]);
592
+ jobs.push(jobConfig);
593
+ }
594
+ }
595
+ });
596
+ }
597
+ else if (propName === 'preProcessors' && value && Node.isArrayLiteralExpression(value)) {
598
+ value.getElements().forEach((element) => {
599
+ if (Node.isIdentifier(element)) {
600
+ preProcessors.push({ ref: element.getText() });
601
+ }
602
+ else if (Node.isNewExpression(element)) {
603
+ const processorArgs = element.getArguments();
604
+ if (processorArgs.length > 0 && Node.isObjectLiteralExpression(processorArgs[0])) {
605
+ const processorConfig = extractConfigFromObjectLiteral(processorArgs[0]);
606
+ preProcessors.push(processorConfig);
607
+ }
608
+ }
609
+ });
610
+ }
611
+ else if (propName === 'postProcessors' && value && Node.isArrayLiteralExpression(value)) {
612
+ value.getElements().forEach((element) => {
613
+ if (Node.isIdentifier(element)) {
614
+ postProcessors.push({ ref: element.getText() });
615
+ }
616
+ else if (Node.isNewExpression(element)) {
617
+ const processorArgs = element.getArguments();
618
+ if (processorArgs.length > 0 && Node.isObjectLiteralExpression(processorArgs[0])) {
619
+ const processorConfig = extractConfigFromObjectLiteral(processorArgs[0]);
620
+ postProcessors.push(processorConfig);
621
+ }
622
+ }
623
+ });
624
+ }
625
+ }
626
+ });
627
+ if (name && persona) {
628
+ agentMetadata = {
629
+ name,
630
+ persona,
631
+ welcomeMessage: welcomeMessage || undefined,
632
+ skills,
633
+ webhooks,
634
+ jobs,
635
+ preProcessors,
636
+ postProcessors
637
+ };
638
+ }
639
+ }
640
+ }
641
+ }
642
+ });
643
+ return agentMetadata;
644
+ }
645
+ /**
646
+ * Helper function to extract configuration from an object literal expression.
647
+ * Used by extractLuaAgentMetadata to parse inline skill/webhook/job definitions.
648
+ * Handles nested objects, arrays, and various data types.
649
+ */
650
+ function extractConfigFromObjectLiteral(configObj) {
651
+ const config = {};
652
+ configObj.getProperties().forEach((prop) => {
653
+ if (Node.isPropertyAssignment(prop)) {
654
+ const name = prop.getName();
655
+ const value = prop.getInitializer();
656
+ if (value) {
657
+ config[name] = extractValueFromNode(value);
658
+ }
659
+ }
660
+ });
661
+ return config;
662
+ }
663
+ /**
664
+ * Extracts a value from an AST node, handling various types.
665
+ */
666
+ function extractValueFromNode(node) {
667
+ if (!node)
668
+ return undefined;
669
+ // String literal
670
+ if (Node.isStringLiteral(node)) {
671
+ return node.getLiteralValue();
672
+ }
673
+ // Numeric literal
674
+ if (Node.isNumericLiteral(node)) {
675
+ return node.getLiteralValue();
676
+ }
677
+ // Boolean literal
678
+ if (node.getKind() === 110 || node.getKind() === 95) { // TrueKeyword or FalseKeyword
679
+ return node.getText() === 'true';
680
+ }
681
+ // New expression (for tools: [new ToolClass()])
682
+ // Extract just the class name for compatibility with buildSkillsArray
683
+ if (Node.isNewExpression(node)) {
684
+ const expression = node.getExpression();
685
+ return expression.getText(); // Returns class name like "GetWeatherTool"
686
+ }
687
+ // Array literal
688
+ if (Node.isArrayLiteralExpression(node)) {
689
+ return node.getElements().map((element) => extractValueFromNode(element));
690
+ }
691
+ // Object literal
692
+ if (Node.isObjectLiteralExpression(node)) {
693
+ return extractConfigFromObjectLiteral(node);
694
+ }
695
+ // Arrow function or function expression (for execute, etc.)
696
+ if (Node.isArrowFunction(node) || Node.isFunctionExpression(node)) {
697
+ return node.getText(); // Return the function as a string
698
+ }
699
+ // Template literal or other complex expressions
700
+ // For persona, context, etc. that might be multiline
701
+ const text = node.getText();
702
+ // If it starts with a quote, remove quotes
703
+ if ((text.startsWith('"') && text.endsWith('"')) ||
704
+ (text.startsWith("'") && text.endsWith("'")) ||
705
+ (text.startsWith('`') && text.endsWith('`'))) {
706
+ return text.slice(1, -1).replace(/\\n/g, '\n');
707
+ }
708
+ return text;
709
+ }
710
+ /**
711
+ * Gets the file paths where skills are defined in a LuaAgent.
712
+ * This is used to scan those files for tools.
713
+ * Returns deduplicated file paths.
714
+ *
715
+ * @param agentMetadata - Agent metadata from extractLuaAgentMetadata
716
+ * @param indexFile - The index source file
717
+ * @returns Array of unique file paths where skills are defined
718
+ */
719
+ export function getSkillFilePaths(agentMetadata, indexFile) {
720
+ const filePathsSet = new Set();
721
+ const imports = indexFile.getImportDeclarations();
722
+ for (const skill of agentMetadata.skills) {
723
+ if (skill.ref) {
724
+ // Find where this skill is imported from
725
+ for (const importDecl of imports) {
726
+ const namedImports = importDecl.getNamedImports();
727
+ const defaultImport = importDecl.getDefaultImport();
728
+ let isMatch = false;
729
+ // Check named imports
730
+ for (const namedImport of namedImports) {
731
+ if (namedImport.getName() === skill.ref) {
732
+ isMatch = true;
733
+ break;
734
+ }
735
+ }
736
+ // Check default import
737
+ if (!isMatch && defaultImport && defaultImport.getText() === skill.ref) {
738
+ isMatch = true;
739
+ }
740
+ if (isMatch) {
741
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
742
+ const importPath = resolveImportPath(moduleSpecifier, indexFile.getFilePath());
743
+ if (fs.existsSync(importPath)) {
744
+ filePathsSet.add(importPath); // Use Set to avoid duplicates
745
+ }
746
+ break;
747
+ }
748
+ }
749
+ }
750
+ }
751
+ return Array.from(filePathsSet);
752
+ }
753
+ /**
754
+ * Resolves references in LuaAgent metadata to actual definitions.
755
+ * When a LuaAgent contains references like `skills: [userSkill]`, this function
756
+ * finds where `userSkill` is defined and extracts its metadata.
757
+ */
758
+ export function resolveLuaAgentReferences(agentMetadata, indexFile, project) {
759
+ const resolveArrayReferences = (items, extractFunction) => {
760
+ const resolved = [];
761
+ for (const item of items) {
762
+ if (item.ref) {
763
+ // This is a reference, need to resolve it
764
+ const varName = item.ref;
765
+ // Find the variable declaration in the index file
766
+ const varDecl = findVariableDeclaration(indexFile, varName);
767
+ if (varDecl) {
768
+ // If it's a new expression, extract metadata
769
+ const initializer = varDecl.getInitializer();
770
+ if (initializer && Node.isNewExpression(initializer)) {
771
+ const expression = initializer.getExpression();
772
+ const args = initializer.getArguments();
773
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
774
+ const config = extractConfigFromObjectLiteral(args[0]);
775
+ resolved.push(config);
776
+ }
777
+ }
778
+ }
779
+ else {
780
+ // Check if it's imported from another file
781
+ const importedMetadata = findImportedDefinition(indexFile, varName, project, extractFunction);
782
+ if (importedMetadata) {
783
+ resolved.push(...importedMetadata);
784
+ }
785
+ }
786
+ }
787
+ else {
788
+ // Not a reference, already has metadata
789
+ resolved.push(item);
790
+ }
791
+ }
792
+ return resolved;
793
+ };
794
+ return {
795
+ skills: resolveArrayReferences(agentMetadata.skills, extractSkillsMetadata),
796
+ webhooks: resolveArrayReferences(agentMetadata.webhooks, extractWebhooksMetadata),
797
+ jobs: resolveArrayReferences(agentMetadata.jobs, extractJobsMetadata),
798
+ preProcessors: resolveArrayReferences(agentMetadata.preProcessors, extractPreProcessorsMetadata),
799
+ postProcessors: resolveArrayReferences(agentMetadata.postProcessors, extractPostProcessorsMetadata)
800
+ };
801
+ }
802
+ /**
803
+ * Finds a variable declaration in a source file by name.
804
+ */
805
+ function findVariableDeclaration(sourceFile, varName) {
806
+ const declarations = sourceFile.getVariableDeclarations();
807
+ for (const decl of declarations) {
808
+ if (decl.getName() === varName) {
809
+ return decl;
810
+ }
811
+ }
812
+ return null;
813
+ }
814
+ /**
815
+ * Finds an imported definition and extracts its metadata.
816
+ * This directly extracts the config from the variable declaration in the imported file.
817
+ * Handles both named imports and default imports.
818
+ */
819
+ function findImportedDefinition(sourceFile, varName, project, extractFunction) {
820
+ const imports = sourceFile.getImportDeclarations();
821
+ for (const importDecl of imports) {
822
+ let isMatch = false;
823
+ // Check named imports: import { varName } from '...'
824
+ const namedImports = importDecl.getNamedImports();
825
+ for (const namedImport of namedImports) {
826
+ if (namedImport.getName() === varName) {
827
+ isMatch = true;
828
+ break;
829
+ }
830
+ }
831
+ // Check default import: import varName from '...'
832
+ if (!isMatch) {
833
+ const defaultImport = importDecl.getDefaultImport();
834
+ if (defaultImport && defaultImport.getText() === varName) {
835
+ isMatch = true;
836
+ }
837
+ }
838
+ if (isMatch) {
839
+ // Found the import, resolve the file
840
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
841
+ const importPath = resolveImportPath(moduleSpecifier, sourceFile.getFilePath());
842
+ if (fs.existsSync(importPath)) {
843
+ try {
844
+ const importedFile = project.addSourceFileAtPath(importPath);
845
+ // Strategy 1: Look for a variable declaration with the same name
846
+ let varDecl = importedFile.getVariableDeclaration(varName);
847
+ // Strategy 2: If it's a default import, look for default export
848
+ if (!varDecl) {
849
+ // Find any variable declaration with default export
850
+ const allVarDecls = importedFile.getVariableDeclarations();
851
+ for (const decl of allVarDecls) {
852
+ // Check if this is exported as default
853
+ const statement = decl.getVariableStatement();
854
+ if (statement && statement.hasDefaultKeyword()) {
855
+ varDecl = decl;
856
+ break;
857
+ }
858
+ }
859
+ // If still not found, just take the first variable declaration
860
+ if (!varDecl && allVarDecls.length > 0) {
861
+ varDecl = allVarDecls[0];
862
+ }
863
+ }
864
+ if (varDecl) {
865
+ const initializer = varDecl.getInitializer();
866
+ // Check if it's a new expression (new LuaSkill, new LuaJob, etc.)
867
+ if (initializer && Node.isNewExpression(initializer)) {
868
+ const args = initializer.getArguments();
869
+ if (args.length > 0 && Node.isObjectLiteralExpression(args[0])) {
870
+ // Extract configuration from the object literal
871
+ const config = extractConfigFromObjectLiteral(args[0]);
872
+ return [config];
873
+ }
874
+ }
875
+ }
876
+ // Fallback: use the extract function to scan the whole file
877
+ const metadata = extractFunction(importedFile);
878
+ if (metadata.length > 0) {
879
+ // Try to find a match by name
880
+ const matchingItem = metadata.find((item) => {
881
+ return item.name && item.name.toLowerCase().includes(varName.toLowerCase().replace('skill', '').replace('job', '').replace('webhook', ''));
882
+ });
883
+ if (matchingItem) {
884
+ return [matchingItem];
885
+ }
886
+ // Return first item as fallback
887
+ return [metadata[0]];
888
+ }
889
+ }
890
+ catch (error) {
891
+ console.warn(`Warning: Could not resolve import ${varName} from ${importPath}:`, error);
892
+ }
893
+ }
894
+ }
895
+ }
896
+ return null;
897
+ }