lua-cli 3.1.0 → 3.2.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 (53) hide show
  1. package/README.md +2 -5
  2. package/dist/api/marketplace.api.service.d.ts +4 -2
  3. package/dist/api/marketplace.api.service.js +6 -0
  4. package/dist/api/persona.api.service.d.ts +54 -0
  5. package/dist/api/persona.api.service.js +89 -0
  6. package/dist/api-exports.d.ts +19 -0
  7. package/dist/api-exports.js +21 -0
  8. package/dist/cli/command-definitions.js +29 -1
  9. package/dist/commands/chat.js +2 -3
  10. package/dist/commands/chatClear.d.ts +5 -1
  11. package/dist/commands/chatClear.js +19 -8
  12. package/dist/commands/compile.d.ts +4 -1
  13. package/dist/commands/compile.js +27 -4
  14. package/dist/commands/index.d.ts +1 -0
  15. package/dist/commands/index.js +1 -0
  16. package/dist/commands/init.js +4 -4
  17. package/dist/commands/marketplace.js +87 -42
  18. package/dist/commands/persona.js +7 -49
  19. package/dist/commands/push.js +3 -2
  20. package/dist/commands/sync.d.ts +29 -0
  21. package/dist/commands/sync.js +194 -0
  22. package/dist/commands/test.js +3 -5
  23. package/dist/interfaces/index.d.ts +2 -0
  24. package/dist/interfaces/lua.d.ts +26 -0
  25. package/dist/interfaces/lua.js +5 -0
  26. package/dist/interfaces/marketplace.d.ts +20 -0
  27. package/dist/interfaces/persona.d.ts +42 -0
  28. package/dist/interfaces/persona.js +5 -0
  29. package/dist/interfaces/user.d.ts +21 -0
  30. package/dist/types/index.d.ts +1 -0
  31. package/dist/types/skill.d.ts +1 -3
  32. package/dist/types/skill.js +3 -32
  33. package/dist/utils/agent-code-utils.d.ts +24 -0
  34. package/dist/utils/agent-code-utils.js +96 -0
  35. package/dist/utils/compile.js +8 -8
  36. package/dist/utils/dev-server.js +5 -4
  37. package/dist/utils/files.d.ts +1 -3
  38. package/dist/utils/files.js +1 -39
  39. package/dist/utils/init-helpers.d.ts +0 -8
  40. package/dist/utils/init-helpers.js +4 -37
  41. package/dist/utils/job-management.js +1 -2
  42. package/dist/utils/sandbox.d.ts +4 -3
  43. package/dist/utils/sandbox.js +5 -9
  44. package/dist/utils/sync-helpers.d.ts +61 -0
  45. package/dist/utils/sync-helpers.js +190 -0
  46. package/dist/utils/test-helpers.d.ts +0 -7
  47. package/dist/utils/test-helpers.js +0 -9
  48. package/package.json +3 -1
  49. package/template/README.md +1 -1
  50. package/template/lua.skill.yaml +10 -0
  51. package/template/package.json +1 -1
  52. package/dist/utils/agent-management.d.ts +0 -23
  53. package/dist/utils/agent-management.js +0 -67
@@ -897,8 +897,9 @@ async function handleInstallerActions(marketplaceApi, config, apiKey) {
897
897
  }
898
898
  }
899
899
  }
900
+ const MARKETPLACE_PAGE_SIZE = 10;
900
901
  /**
901
- * Browse and select a skill from marketplace (with optional search)
902
+ * Browse and select a skill from marketplace (with optional search and pagination)
902
903
  * Returns the selected skill or null if cancelled
903
904
  */
904
905
  async function browseAndSelectSkill(marketplaceApi, purpose, publishedVersionsOnly) {
@@ -914,49 +915,93 @@ async function browseAndSelectSkill(marketplaceApi, purpose, publishedVersionsOn
914
915
  if (searchAnswer === null)
915
916
  return null; // User cancelled
916
917
  const searchQuery = searchAnswer?.query?.trim() || "";
917
- // 2. Search/browse marketplace skills
918
- writeProgress(searchQuery
919
- ? `\nšŸ” Searching for "${searchQuery}"...`
920
- : "\nšŸ” Loading marketplace skills...");
921
- const filters = {};
922
- if (searchQuery)
923
- filters.search = searchQuery;
924
- if (publishedVersionsOnly !== undefined)
925
- filters.publishedVersionsOnly = publishedVersionsOnly;
926
- const searchResults = await marketplaceApi.searchSkills(Object.keys(filters).length > 0 ? filters : undefined);
927
- const skills = searchResults || [];
928
- if (skills.length === 0) {
929
- if (searchQuery) {
930
- writeInfo(`\nšŸ“¦ No skills found matching "${searchQuery}".`);
918
+ let currentPage = 1;
919
+ // Pagination loop
920
+ while (true) {
921
+ // 2. Search/browse marketplace skills with pagination
922
+ writeProgress(searchQuery
923
+ ? `\nšŸ” Searching for "${searchQuery}"...`
924
+ : "\nšŸ” Loading marketplace skills...");
925
+ const filters = {
926
+ limit: MARKETPLACE_PAGE_SIZE,
927
+ page: currentPage
928
+ };
929
+ if (searchQuery)
930
+ filters.search = searchQuery;
931
+ if (publishedVersionsOnly !== undefined)
932
+ filters.publishedVersionsOnly = publishedVersionsOnly;
933
+ const searchResults = await marketplaceApi.searchSkills(filters);
934
+ const skills = searchResults?.data || [];
935
+ const pagination = searchResults?.pagination;
936
+ const totalCount = pagination?.totalCount || skills.length;
937
+ const totalPages = pagination?.totalPages || 1;
938
+ const hasNextPage = pagination?.hasNextPage || false;
939
+ const hasPrevPage = pagination?.hasPrevPage || false;
940
+ if (skills.length === 0 && currentPage === 1) {
941
+ if (searchQuery) {
942
+ writeInfo(`\nšŸ“¦ No skills found matching "${searchQuery}".`);
943
+ }
944
+ else {
945
+ writeInfo("\nšŸ“¦ No skills available on the marketplace yet.");
946
+ }
947
+ writeInfo("šŸ’” Be the first to publish a skill!\n");
948
+ return null;
931
949
  }
932
- else {
933
- writeInfo("\nšŸ“¦ No skills available on the marketplace yet.");
950
+ // 3. Display results with pagination info
951
+ const pageInfo = totalPages > 1 ? ` (Page ${currentPage}/${totalPages})` : "";
952
+ console.log(`\nšŸ“Š Found ${totalCount} skill${totalCount === 1 ? "" : "s"}${pageInfo}:\n`);
953
+ // 4. Build choices with pagination navigation
954
+ const choices = [
955
+ ...skills.map((s) => ({
956
+ name: `${s.displayName} - ${s.description || "No description"}`,
957
+ value: { type: "skill", skill: s },
958
+ })),
959
+ ];
960
+ // Add pagination options
961
+ if (hasNextPage || hasPrevPage) {
962
+ choices.push(new inquirer.Separator());
963
+ if (hasPrevPage) {
964
+ choices.push({
965
+ name: `← Previous page (${currentPage - 1}/${totalPages})`,
966
+ value: { type: "prev" }
967
+ });
968
+ }
969
+ if (hasNextPage) {
970
+ choices.push({
971
+ name: `→ Next page (${currentPage + 1}/${totalPages})`,
972
+ value: { type: "next" }
973
+ });
974
+ }
975
+ }
976
+ choices.push(new inquirer.Separator());
977
+ choices.push({ name: "← Back to menu", value: { type: "back" } });
978
+ // 5. Prompt user to select
979
+ const message = purpose || "Select a skill:";
980
+ const answer = await safePrompt([
981
+ {
982
+ type: "list",
983
+ name: "selection",
984
+ message,
985
+ choices,
986
+ pageSize: MARKETPLACE_PAGE_SIZE + 5, // Show all items + navigation options
987
+ },
988
+ ]);
989
+ if (!answer || !answer.selection)
990
+ return null;
991
+ const { selection } = answer;
992
+ if (selection.type === "skill" && selection.skill) {
993
+ return selection.skill;
994
+ }
995
+ else if (selection.type === "next") {
996
+ currentPage++;
997
+ }
998
+ else if (selection.type === "prev") {
999
+ currentPage--;
1000
+ }
1001
+ else if (selection.type === "back") {
1002
+ return null;
934
1003
  }
935
- writeInfo("šŸ’” Be the first to publish a skill!\n");
936
- return null;
937
1004
  }
938
- // 3. Display results
939
- console.log(`\nšŸ“Š Found ${skills.length} skill${skills.length === 1 ? "" : "s"}:\n`);
940
- // 4. Prompt user to select a skill
941
- const message = purpose || "Select a skill (or press ESC to go back):";
942
- const skillAnswer = await safePrompt([
943
- {
944
- type: "list",
945
- name: "skill",
946
- message,
947
- choices: [
948
- ...skills.map((s) => ({
949
- name: `${s.displayName} - ${s.description || "No description"}`,
950
- value: s,
951
- })),
952
- new inquirer.Separator(),
953
- { name: "← Back to menu", value: null },
954
- ],
955
- },
956
- ]);
957
- if (!skillAnswer || !skillAnswer.skill)
958
- return null;
959
- return skillAnswer.skill;
960
1005
  }
961
1006
  catch (error) {
962
1007
  console.error(`\nāŒ Error browsing marketplace: ${error.message}\n`);
@@ -1123,7 +1168,7 @@ async function installMarketplaceSkill(marketplaceApi, config, apiKey) {
1123
1168
  creatorId: directAnswer.creatorId,
1124
1169
  publishedVersionsOnly: true,
1125
1170
  });
1126
- const skills = searchResults || [];
1171
+ const skills = searchResults?.data || [];
1127
1172
  if (skills.length === 0) {
1128
1173
  console.error(`\nāŒ Skill "${directAnswer.name}" by creator "${directAnswer.creatorId}" not found on the marketplace.\n`);
1129
1174
  return;
@@ -2,9 +2,6 @@
2
2
  * Persona Command
3
3
  * Manages agent persona for sandbox and production environments
4
4
  */
5
- import fs from 'fs';
6
- import path from 'path';
7
- import yaml from 'js-yaml';
8
5
  import inquirer from 'inquirer';
9
6
  import { loadApiKey, checkApiKey } from '../services/auth.js';
10
7
  import { readSkillConfig } from '../utils/files.js';
@@ -12,6 +9,7 @@ import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../ut
12
9
  import { BASE_URLS } from '../config/constants.js';
13
10
  import { safePrompt } from '../utils/prompt-handler.js';
14
11
  import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
12
+ import { loadPersonaFromCode, savePersonaToCode } from '../utils/agent-code-utils.js';
15
13
  /**
16
14
  * Main persona command - manages agent persona
17
15
  *
@@ -96,8 +94,8 @@ export async function personaCommand(env) {
96
94
  async function manageSandboxPersona(context) {
97
95
  let continueManaging = true;
98
96
  while (continueManaging) {
99
- // Load current persona
100
- const currentPersona = loadSandboxPersona();
97
+ // Load current persona directly from code
98
+ const currentPersona = loadPersonaFromCode();
101
99
  // Show menu
102
100
  console.log("\n" + "=".repeat(60));
103
101
  console.log("šŸŒ™ Sandbox Persona Management");
@@ -188,46 +186,6 @@ async function manageProductionPersona(context) {
188
186
  }
189
187
  }
190
188
  }
191
- /**
192
- * Load sandbox persona from lua.skill.yaml
193
- */
194
- function loadSandboxPersona() {
195
- try {
196
- const config = readSkillConfig();
197
- return config.agent?.persona || '';
198
- }
199
- catch (error) {
200
- return '';
201
- }
202
- }
203
- /**
204
- * Save sandbox persona to lua.skill.yaml
205
- */
206
- function saveSandboxPersona(persona) {
207
- try {
208
- const configPath = path.join(process.cwd(), 'lua.skill.yaml');
209
- // Read current config
210
- const fileContent = fs.readFileSync(configPath, 'utf8');
211
- const config = yaml.load(fileContent);
212
- // Ensure agent object exists
213
- if (!config.agent) {
214
- config.agent = {};
215
- }
216
- // Update persona
217
- config.agent.persona = persona;
218
- // Write back to file
219
- const newContent = yaml.dump(config, {
220
- lineWidth: -1,
221
- noRefs: true
222
- });
223
- fs.writeFileSync(configPath, newContent, 'utf8');
224
- return true;
225
- }
226
- catch (error) {
227
- console.error('āŒ Error saving persona to lua.skill.yaml:', error);
228
- return false;
229
- }
230
- }
231
189
  /**
232
190
  * View full persona content
233
191
  */
@@ -287,13 +245,13 @@ async function editSandboxPersona(context, currentPersona) {
287
245
  return;
288
246
  const { newPersona } = personaAnswer;
289
247
  const trimmedPersona = newPersona.trim();
290
- writeProgress("šŸ”„ Saving persona to lua.skill.yaml...");
291
- const success = saveSandboxPersona(trimmedPersona);
248
+ writeProgress("šŸ”„ Saving persona to code (LuaAgent)...");
249
+ const success = savePersonaToCode(trimmedPersona);
292
250
  if (success) {
293
- writeSuccess("āœ… Persona saved to lua.skill.yaml successfully");
251
+ writeSuccess("āœ… Persona saved to code successfully");
294
252
  }
295
253
  else {
296
- console.error("āŒ Failed to save persona to lua.skill.yaml");
254
+ console.error("āŒ Failed to save persona to code");
297
255
  }
298
256
  }
299
257
  /**
@@ -17,6 +17,7 @@ import { BASE_URLS } from '../config/constants.js';
17
17
  import PreProcessorApi from '../api/preprocessor.api.service.js';
18
18
  import PostProcessorApi from '../api/postprocessor.api.service.js';
19
19
  import DeveloperApi from '../api/developer.api.service.js';
20
+ import { loadPersonaFromCode } from '../utils/agent-code-utils.js';
20
21
  /**
21
22
  * Main push command - pushes a skill or persona version to the server.
22
23
  *
@@ -239,8 +240,8 @@ async function pushPersonaVersion() {
239
240
  console.error("āŒ No agent configuration found. Please run 'lua init' first.");
240
241
  process.exit(1);
241
242
  }
242
- // Step 2: Load current persona
243
- const currentPersona = config.agent?.persona || '';
243
+ // Step 2: Load current persona from code
244
+ const currentPersona = loadPersonaFromCode();
244
245
  if (!currentPersona || !currentPersona.trim()) {
245
246
  console.error("āŒ No persona found in configuration. Please edit your persona first using 'lua persona'.");
246
247
  process.exit(1);
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Sync Command
3
+ * Detects drift between server state and local code, allowing users to sync
4
+ */
5
+ /**
6
+ * Main sync command - detects and resolves drift between server and local code.
7
+ *
8
+ * Features:
9
+ * - Fetches current deployed state from server
10
+ * - Compares with local code
11
+ * - Shows diff for drifted components
12
+ * - Allows user to update local code from server
13
+ *
14
+ * @returns Promise that resolves when sync completes
15
+ */
16
+ export declare function syncCommand(): Promise<void>;
17
+ /**
18
+ * Run sync check during compile flow (non-interactive or with prompts).
19
+ * Returns true if compilation should continue, false if user cancelled.
20
+ *
21
+ * @param apiKey - API key for authentication
22
+ * @param agentId - Agent ID
23
+ * @param options - Sync options
24
+ * @returns Promise<boolean> - true to continue, false to cancel
25
+ */
26
+ export declare function runSyncCheck(apiKey: string, agentId: string, options?: {
27
+ noSync?: boolean;
28
+ forceSync?: boolean;
29
+ }): Promise<boolean>;
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Sync Command
3
+ * Detects drift between server state and local code, allowing users to sync
4
+ */
5
+ import { loadApiKey, checkApiKey } from '../services/auth.js';
6
+ import { readSkillConfig } from '../utils/files.js';
7
+ import { withErrorHandling, writeProgress, writeSuccess, writeInfo } from '../utils/cli.js';
8
+ import { safePrompt } from '../utils/prompt-handler.js';
9
+ import { validateConfig, validateAgentConfig, } from '../utils/dev-helpers.js';
10
+ import { savePersonaToCode, saveNameToCode } from '../utils/agent-code-utils.js';
11
+ import { checkPersonaDrift, checkNameDrift, showPersonaDiff, showNameDiff, } from '../utils/sync-helpers.js';
12
+ /**
13
+ * Main sync command - detects and resolves drift between server and local code.
14
+ *
15
+ * Features:
16
+ * - Fetches current deployed state from server
17
+ * - Compares with local code
18
+ * - Shows diff for drifted components
19
+ * - Allows user to update local code from server
20
+ *
21
+ * @returns Promise that resolves when sync completes
22
+ */
23
+ export async function syncCommand() {
24
+ return withErrorHandling(async () => {
25
+ writeProgress('šŸ”„ Checking for drift between server and local code...');
26
+ // Step 1: Load configuration
27
+ const config = readSkillConfig();
28
+ validateConfig(config);
29
+ validateAgentConfig(config);
30
+ const agentId = config.agent.agentId;
31
+ // Step 2: Authenticate
32
+ const apiKey = await loadApiKey();
33
+ if (!apiKey) {
34
+ console.error("āŒ No API key found. Please run 'lua auth configure' to set up your API key.");
35
+ process.exit(1);
36
+ }
37
+ await checkApiKey(apiKey);
38
+ // Step 3: Check for drift
39
+ const nameDrift = await checkNameDrift(apiKey, agentId);
40
+ const personaDrift = await checkPersonaDrift(apiKey, agentId);
41
+ if (!nameDrift && !personaDrift) {
42
+ writeSuccess('āœ… No drift detected. Local code is in sync with server.');
43
+ return;
44
+ }
45
+ // Step 4: Handle name drift
46
+ if (nameDrift) {
47
+ await handleNameDrift(nameDrift);
48
+ }
49
+ // Step 5: Handle persona drift
50
+ if (personaDrift) {
51
+ await handlePersonaDrift(personaDrift);
52
+ }
53
+ writeSuccess('\nāœ… Sync complete.');
54
+ }, 'sync');
55
+ }
56
+ /**
57
+ * Handle name drift interactively.
58
+ */
59
+ async function handleNameDrift(drift) {
60
+ showNameDiff(drift.serverName, drift.localName);
61
+ const answer = await safePrompt([
62
+ {
63
+ type: 'list',
64
+ name: 'action',
65
+ message: 'What would you like to do with the name?',
66
+ choices: [
67
+ { name: 'šŸ“„ Update local from server', value: 'update' },
68
+ { name: 'ā­ļø Skip (keep local)', value: 'skip' },
69
+ ],
70
+ },
71
+ ]);
72
+ if (!answer || answer.action === 'skip') {
73
+ writeInfo('Skipped name sync.');
74
+ return;
75
+ }
76
+ if (answer.action === 'update' && drift.serverName) {
77
+ writeProgress('šŸ“ Updating name in code...');
78
+ const success = saveNameToCode(drift.serverName);
79
+ if (success) {
80
+ writeSuccess('āœ… Name updated in src/index.ts');
81
+ }
82
+ else {
83
+ console.error('āŒ Failed to update name in code.');
84
+ }
85
+ }
86
+ }
87
+ /**
88
+ * Handle persona drift interactively.
89
+ */
90
+ async function handlePersonaDrift(drift) {
91
+ // Show diff
92
+ showPersonaDiff(drift.serverPersona, drift.localPersona);
93
+ // Prompt user for action
94
+ const answer = await safePrompt([
95
+ {
96
+ type: 'list',
97
+ name: 'action',
98
+ message: 'What would you like to do with persona?',
99
+ choices: [
100
+ { name: 'šŸ“„ Update local from server', value: 'update' },
101
+ { name: 'ā­ļø Skip (keep local)', value: 'skip' },
102
+ ],
103
+ },
104
+ ]);
105
+ if (!answer || answer.action === 'skip') {
106
+ writeInfo('Skipped persona sync.');
107
+ return;
108
+ }
109
+ if (answer.action === 'update') {
110
+ if (drift.serverPersona) {
111
+ writeProgress('šŸ“ Updating persona in code...');
112
+ const success = savePersonaToCode(drift.serverPersona);
113
+ if (success) {
114
+ writeSuccess('āœ… Persona updated in src/index.ts');
115
+ }
116
+ else {
117
+ console.error('āŒ Failed to update persona in code.');
118
+ }
119
+ }
120
+ else {
121
+ writeInfo('ā„¹ļø No server persona to sync from.');
122
+ }
123
+ }
124
+ }
125
+ /**
126
+ * Run sync check during compile flow (non-interactive or with prompts).
127
+ * Returns true if compilation should continue, false if user cancelled.
128
+ *
129
+ * @param apiKey - API key for authentication
130
+ * @param agentId - Agent ID
131
+ * @param options - Sync options
132
+ * @returns Promise<boolean> - true to continue, false to cancel
133
+ */
134
+ export async function runSyncCheck(apiKey, agentId, options = {}) {
135
+ // Skip sync if --no-sync flag is set
136
+ if (options.noSync) {
137
+ return true;
138
+ }
139
+ // Check for drift
140
+ const nameDrift = await checkNameDrift(apiKey, agentId);
141
+ const personaDrift = await checkPersonaDrift(apiKey, agentId);
142
+ if (!nameDrift && !personaDrift) {
143
+ return true; // No drift, continue
144
+ }
145
+ // If --force-sync, auto-update without prompting
146
+ if (options.forceSync) {
147
+ if (nameDrift?.serverName) {
148
+ writeProgress('šŸ”„ Auto-syncing name from server (--force-sync)...');
149
+ saveNameToCode(nameDrift.serverName);
150
+ writeSuccess('āœ… Name synced from server');
151
+ }
152
+ if (personaDrift?.serverPersona) {
153
+ writeProgress('šŸ”„ Auto-syncing persona from server (--force-sync)...');
154
+ savePersonaToCode(personaDrift.serverPersona);
155
+ writeSuccess('āœ… Persona synced from server');
156
+ }
157
+ return true;
158
+ }
159
+ // Show diffs
160
+ console.log('\nāš ļø Drift detected!\n');
161
+ if (nameDrift) {
162
+ showNameDiff(nameDrift.serverName, nameDrift.localName);
163
+ }
164
+ if (personaDrift) {
165
+ showPersonaDiff(personaDrift.serverPersona, personaDrift.localPersona);
166
+ }
167
+ const answer = await safePrompt([
168
+ {
169
+ type: 'list',
170
+ name: 'action',
171
+ message: 'How would you like to proceed?',
172
+ choices: [
173
+ { name: 'šŸ“„ Update local from server', value: 'update' },
174
+ { name: 'ā­ļø Continue with local (will overwrite server on push)', value: 'continue' },
175
+ { name: 'āŒ Cancel', value: 'cancel' },
176
+ ],
177
+ },
178
+ ]);
179
+ if (!answer || answer.action === 'cancel') {
180
+ console.log('\nāŒ Compilation cancelled due to unresolved drift.');
181
+ return false;
182
+ }
183
+ if (answer.action === 'update') {
184
+ if (nameDrift?.serverName) {
185
+ saveNameToCode(nameDrift.serverName);
186
+ writeSuccess('āœ… Name synced from server');
187
+ }
188
+ if (personaDrift?.serverPersona) {
189
+ savePersonaToCode(personaDrift.serverPersona);
190
+ writeSuccess('āœ… Persona synced from server');
191
+ }
192
+ }
193
+ return true;
194
+ }
@@ -10,7 +10,7 @@ import { loadApiKey } from "../services/auth.js";
10
10
  import { executeTool, executeWebhook, executeJob, executePreProcessor, executePostProcessor, loadEnvironmentVariables } from "../utils/sandbox.js";
11
11
  import { readSkillConfig } from "../utils/files.js";
12
12
  import { safePrompt } from "../utils/prompt-handler.js";
13
- import { decompressCode, readDeployJson, extractToolsFromDeployData, hasEnvFile, hasConfigEnvVars, } from "../utils/test-helpers.js";
13
+ import { decompressCode, readDeployJson, extractToolsFromDeployData, hasEnvFile, } from "../utils/test-helpers.js";
14
14
  import { promptToolSelection, generatePromptsForObject } from "../utils/test-prompts.js";
15
15
  /**
16
16
  * Main test command - tests tools, webhooks, jobs, preprocessors, or postprocessors.
@@ -110,9 +110,6 @@ async function testSkill() {
110
110
  if (hasEnvFile()) {
111
111
  writeProgress(`šŸ“„ Loaded environment variables from .env file`);
112
112
  }
113
- if (hasConfigEnvVars(config)) {
114
- writeProgress(`šŸ“„ Loaded environment variables from lua.skill.yaml`);
115
- }
116
113
  // Step 5: Let user select a tool
117
114
  const selectedTool = await promptToolSelection(allTools);
118
115
  clearPromptLines(2);
@@ -138,7 +135,8 @@ async function testSkill() {
138
135
  toolCode,
139
136
  inputs: inputValues,
140
137
  apiKey,
141
- agentId
138
+ agentId,
139
+ channel: 'dev',
142
140
  });
143
141
  writeSuccess("āœ… Tool execution successful!");
144
142
  console.log(`Output: ${JSON.stringify(result, null, 2)}`);
@@ -10,3 +10,5 @@ export { ApiResponse, Pagination } from "./common.js";
10
10
  export { SkillTool, SkillVersion, Skill, GetSkillsResponse, DeleteSkillResponse, } from "./skills.js";
11
11
  export { ImmutableUserProfile, UserAgentData } from "./user.js";
12
12
  export { MCPServerResponse, MCPServerStdioResponse, MCPServerSSEResponse, CreateMCPServerRequest, UpdateMCPServerRequest, } from "./mcp.js";
13
+ export { PersonaVersion, PersonaVersionsResponse, CreatePersonaVersionResponse, SetPersonaVersionResponse, } from "./persona.js";
14
+ export { Channel, LuaRequest, LuaRuntime, } from "./lua.js";
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Lua Runtime Interfaces
3
+ * Request-level runtime information available in the execution sandbox
4
+ */
5
+ /**
6
+ * Channel type.
7
+ * Represents the communication channel through which a request originated.
8
+ * Known channels are typed as string literals, unrecognized channels are unknown.
9
+ */
10
+ export type Channel = 'web' | 'whatsapp' | 'facebook' | 'instagram' | 'slack' | 'api' | 'dev' | 'email' | string;
11
+ /**
12
+ * Lua request context.
13
+ * Contains information about the current request.
14
+ */
15
+ export interface LuaRequest {
16
+ /** The channel through which the request originated */
17
+ channel: Channel;
18
+ }
19
+ /**
20
+ * Lua runtime API.
21
+ * Provides access to request-level runtime information.
22
+ */
23
+ export interface LuaRuntime {
24
+ /** Request context information */
25
+ request: LuaRequest;
26
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Lua Runtime Interfaces
3
+ * Request-level runtime information available in the execution sandbox
4
+ */
5
+ export {};
@@ -97,3 +97,23 @@ export interface UnlistSkillResponse {
97
97
  unlisted: boolean;
98
98
  versionsUnpublished: number;
99
99
  }
100
+ /**
101
+ * Pagination metadata
102
+ */
103
+ export interface MarketplacePaginationResponse {
104
+ currentPage: number;
105
+ totalPages: number;
106
+ totalCount: number;
107
+ limit: number;
108
+ hasNextPage: boolean;
109
+ hasPrevPage: boolean;
110
+ nextPage: number | null;
111
+ prevPage: number | null;
112
+ }
113
+ /**
114
+ * Paginated marketplace skills response
115
+ */
116
+ export interface PaginatedMarketplaceSkillsResponse {
117
+ data: MarketplaceSkillWithVersionsResponse[];
118
+ pagination: MarketplacePaginationResponse;
119
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Persona Interfaces
3
+ * Matches lua-api/src/dto/persona.dto.ts
4
+ */
5
+ /**
6
+ * Persona version structure
7
+ * Matches PersonaVersionDto
8
+ */
9
+ export interface PersonaVersion {
10
+ version: number;
11
+ persona: string;
12
+ createdDate: number;
13
+ createdBy?: string;
14
+ isCurrent: boolean;
15
+ }
16
+ /**
17
+ * Response for getVersions
18
+ * Matches PersonaVersionsResponseDto
19
+ */
20
+ export interface PersonaVersionsResponse {
21
+ status: string;
22
+ message: string;
23
+ versions: PersonaVersion[];
24
+ }
25
+ /**
26
+ * Response for createVersion
27
+ * Matches CreatePersonaVersionResponseDto
28
+ */
29
+ export interface CreatePersonaVersionResponse {
30
+ status: string;
31
+ message: string;
32
+ version: number;
33
+ }
34
+ /**
35
+ * Response for deployVersion (setPersonaVersion)
36
+ * Matches SetPersonaVersionResponseDto
37
+ */
38
+ export interface SetPersonaVersionResponse {
39
+ status: string;
40
+ message: string;
41
+ version: number;
42
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Persona Interfaces
3
+ * Matches lua-api/src/dto/persona.dto.ts
4
+ */
5
+ export {};
@@ -17,3 +17,24 @@ export interface UserAgentData extends Record<string, any> {
17
17
  */
18
18
  userId?: string;
19
19
  }
20
+ /**
21
+ * Profile response from user lookup endpoints
22
+ */
23
+ export interface ProfileResponse {
24
+ id: string;
25
+ fullName: string;
26
+ mobileNumbers: Array<{
27
+ number: string;
28
+ validated: boolean;
29
+ validatedAt: number;
30
+ }>;
31
+ emailAddresses: Array<{
32
+ address: string;
33
+ validated: boolean;
34
+ validatedAt: number;
35
+ }>;
36
+ country?: {
37
+ code?: string;
38
+ name?: string;
39
+ };
40
+ }
@@ -23,3 +23,4 @@ export { BasketStatus, BasketItem, Basket } from '../interfaces/baskets.js';
23
23
  export { OrderStatus, OrderResponse } from '../interfaces/orders.js';
24
24
  export { Product } from '../interfaces/product.js';
25
25
  export { ApiResponse, Pagination } from '../interfaces/common.js';
26
+ export { Channel, LuaRequest, LuaRuntime } from '../interfaces/lua.js';
@@ -9,9 +9,7 @@ import { JobInstance } from "../common/job.instance.js";
9
9
  * Safe environment variable access function.
10
10
  * Gets injected at runtime with skill-specific environment variables.
11
11
  *
12
- * Checks in order:
13
- * 1. Process environment variables (.env file)
14
- * 2. lua.skill.yaml configuration
12
+ * Checks process environment variables (.env file)
15
13
  *
16
14
  * @param key - The environment variable key to retrieve
17
15
  * @returns The environment variable value or undefined if not found