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
@@ -21,5 +21,6 @@ export declare function createDeploymentData(tools: ToolInfo[], distDir: string)
21
21
  * @param tools - Array of detected tools
22
22
  * @param luaDir - Legacy .lua directory for output
23
23
  * @param indexFile - The TypeScript source file for the index
24
+ * @param agentData - Optional resolved agent data from LuaAgent (for new approach)
24
25
  */
25
- export declare function createLegacyDeploymentData(tools: ToolInfo[], luaDir: string, indexFile: TypeScriptSourceFile): Promise<void>;
26
+ export declare function createLegacyDeploymentData(tools: ToolInfo[], luaDir: string, indexFile: TypeScriptSourceFile, agentData?: any): Promise<void>;
@@ -52,10 +52,24 @@ function readPackageJson() {
52
52
  * @param tools - Array of detected tools
53
53
  * @param luaDir - Legacy .lua directory for output
54
54
  * @param indexFile - The TypeScript source file for the index
55
+ * @param agentData - Optional resolved agent data from LuaAgent (for new approach)
55
56
  */
56
- export async function createLegacyDeploymentData(tools, luaDir, indexFile) {
57
+ export async function createLegacyDeploymentData(tools, luaDir, indexFile, agentData) {
57
58
  const config = readSkillConfig();
58
- const skillsMetadata = extractSkillsMetadata(indexFile);
59
+ let skillsMetadata;
60
+ // Check if we have agent data (from LuaAgent approach)
61
+ if (agentData && agentData.skills && agentData.skills.length > 0) {
62
+ // Use skills from LuaAgent
63
+ // Map 'tools' to 'constructorTools' for compatibility with buildSkillsArray
64
+ skillsMetadata = agentData.skills.map((skill) => ({
65
+ ...skill,
66
+ constructorTools: skill.tools || []
67
+ }));
68
+ }
69
+ else {
70
+ // Fall back to legacy approach - extract from index file
71
+ skillsMetadata = extractSkillsMetadata(indexFile);
72
+ }
59
73
  // Map tools to their parent skills
60
74
  const skillToTools = mapToolsToSkills(indexFile);
61
75
  // Build skills array with their associated tools
@@ -28,10 +28,12 @@ export declare function selectBaseAgentType(agentTypes: AgentType[]): AgentType;
28
28
  * @param businessConfig - Business configuration
29
29
  * @param metadata - Agent metadata
30
30
  * @param features - Feature configuration
31
+ * @param existingOrgId - Optional existing organization ID to use
32
+ * @param newOrgName - Optional new organization name (if not using existing)
31
33
  * @returns Agent creation result with agent and org details
32
34
  * @throws Error if agent creation fails
33
35
  */
34
- export declare function createNewAgent(apiKey: string, agentType: AgentType, businessConfig: BusinessConfig, metadata: Record<string, any>, features: Record<string, boolean>): Promise<AgentCreationResult>;
36
+ export declare function createNewAgent(apiKey: string, agentType: AgentType, businessConfig: BusinessConfig, metadata: Record<string, any>, features: Record<string, boolean>, existingOrgId?: string, newOrgName?: string): Promise<AgentCreationResult>;
35
37
  /**
36
38
  * Fetches detailed agent information for an existing agent.
37
39
  * Used when selecting an existing agent during init.
@@ -50,10 +50,12 @@ export function selectBaseAgentType(agentTypes) {
50
50
  * @param businessConfig - Business configuration
51
51
  * @param metadata - Agent metadata
52
52
  * @param features - Feature configuration
53
+ * @param existingOrgId - Optional existing organization ID to use
54
+ * @param newOrgName - Optional new organization name (if not using existing)
53
55
  * @returns Agent creation result with agent and org details
54
56
  * @throws Error if agent creation fails
55
57
  */
56
- export async function createNewAgent(apiKey, agentType, businessConfig, metadata, features) {
58
+ export async function createNewAgent(apiKey, agentType, businessConfig, metadata, features, existingOrgId, newOrgName) {
57
59
  writeProgress("🔄 Creating agent...");
58
60
  const agentData = {
59
61
  id: `agent_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
@@ -67,9 +69,9 @@ export async function createNewAgent(apiKey, agentType, businessConfig, metadata
67
69
  },
68
70
  features,
69
71
  channels: [],
70
- org: {
71
- registeredName: businessConfig.businessName
72
- }
72
+ org: existingOrgId
73
+ ? { id: existingOrgId } // Use existing org
74
+ : { registeredName: newOrgName || businessConfig.businessName } // Create new org
73
75
  };
74
76
  const agentApi = new AgentApi(BASE_URLS.API, apiKey);
75
77
  const createAgentResult = await agentApi.createAgent(agentData);
@@ -42,6 +42,7 @@ export declare function promptFeatureConfiguration(agentType: AgentType): Promis
42
42
  * Prompts for business and agent configuration.
43
43
  * Collects business name, agent name, type, personality, and traits.
44
44
  *
45
+ * @param skipBusinessName - If true, skips business name prompt (for existing orgs)
45
46
  * @returns Complete business configuration
46
47
  */
47
- export declare function promptBusinessConfiguration(): Promise<BusinessConfig>;
48
+ export declare function promptBusinessConfiguration(skipBusinessName?: boolean): Promise<BusinessConfig>;
@@ -115,17 +115,22 @@ export async function promptFeatureConfiguration(agentType) {
115
115
  * Prompts for business and agent configuration.
116
116
  * Collects business name, agent name, type, personality, and traits.
117
117
  *
118
+ * @param skipBusinessName - If true, skips business name prompt (for existing orgs)
118
119
  * @returns Complete business configuration
119
120
  */
120
- export async function promptBusinessConfiguration() {
121
- const { businessName } = await inquirer.prompt([
122
- {
123
- type: "input",
124
- name: "businessName",
125
- message: "Enter business name:",
126
- default: DEFAULT_BUSINESS_NAME
127
- }
128
- ]);
121
+ export async function promptBusinessConfiguration(skipBusinessName = false) {
122
+ let businessName = DEFAULT_BUSINESS_NAME;
123
+ if (!skipBusinessName) {
124
+ const result = await inquirer.prompt([
125
+ {
126
+ type: "input",
127
+ name: "businessName",
128
+ message: "Enter business name:",
129
+ default: DEFAULT_BUSINESS_NAME
130
+ }
131
+ ]);
132
+ businessName = result.businessName;
133
+ }
129
134
  const { agentName } = await inquirer.prompt([
130
135
  {
131
136
  type: "input",
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Job Management Utilities
3
+ * Handles job creation via API and YAML configuration management
4
+ */
5
+ import { SkillConfig } from '../types/compile.types.js';
6
+ /**
7
+ * Ensures all detected jobs exist in the YAML config with valid job IDs.
8
+ * If a job doesn't exist or has no ID, creates it via the API.
9
+ *
10
+ * @param jobsArray - Array of jobs detected from source code
11
+ * @param config - The skill configuration from lua.skill.yaml
12
+ * @returns Updated jobs array with valid job IDs
13
+ */
14
+ export declare function ensureJobsExistInYaml(jobsArray: any[], config: SkillConfig): Promise<any[]>;
15
+ /**
16
+ * Syncs the server jobs with the YAML configuration.
17
+ * Performs a two-way sync:
18
+ * 1. Deletes/deactivates jobs from server that aren't in YAML
19
+ * 2. Updates YAML with active version numbers from server
20
+ *
21
+ * @param config - The skill configuration from lua.skill.yaml
22
+ * @returns Array of messages about sync operations
23
+ */
24
+ export declare function syncServerJobsWithYaml(config: SkillConfig): Promise<string[]>;
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Job Management Utilities
3
+ * Handles job creation via API and YAML configuration management
4
+ */
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import yaml from "js-yaml";
8
+ import JobApi from '../api/job.api.service.js';
9
+ import { BASE_URLS } from '../config/constants.js';
10
+ import { loadApiKey } from '../services/auth.js';
11
+ import { COMPILE_FILES, SKILL_DEFAULTS, YAML_FORMAT, } from '../config/compile.constants.js';
12
+ /**
13
+ * Ensures all detected jobs exist in the YAML config with valid job IDs.
14
+ * If a job doesn't exist or has no ID, creates it via the API.
15
+ *
16
+ * @param jobsArray - Array of jobs detected from source code
17
+ * @param config - The skill configuration from lua.skill.yaml
18
+ * @returns Updated jobs array with valid job IDs
19
+ */
20
+ export async function ensureJobsExistInYaml(jobsArray, config) {
21
+ const updatedJobsArray = [];
22
+ let yamlUpdated = false;
23
+ const existingJobs = config?.jobs || [];
24
+ const existingJobsMap = createJobsMap(existingJobs);
25
+ // Process each detected job
26
+ for (const job of jobsArray) {
27
+ const existingJob = existingJobsMap.get(job.name);
28
+ if (existingJob && existingJob.jobId && existingJob.jobId !== '') {
29
+ // Job exists with valid jobId - reuse it
30
+ updatedJobsArray.push({
31
+ ...job,
32
+ jobId: existingJob.jobId
33
+ });
34
+ }
35
+ else {
36
+ // Job doesn't exist or missing jobId - create via API
37
+ const createdJob = await createJobViaApi(job, config, existingJobs, existingJob);
38
+ updatedJobsArray.push(createdJob);
39
+ yamlUpdated = true;
40
+ }
41
+ }
42
+ // Update YAML file if any changes were made
43
+ if (yamlUpdated) {
44
+ await updateYamlWithJobs(config);
45
+ }
46
+ return updatedJobsArray;
47
+ }
48
+ /**
49
+ * Creates a map of existing jobs for quick lookup by name.
50
+ *
51
+ * @param existingJobs - Array of jobs from YAML config
52
+ * @returns Map of job names to job objects
53
+ */
54
+ function createJobsMap(existingJobs) {
55
+ const map = new Map();
56
+ existingJobs.forEach((job) => {
57
+ map.set(job.name, job);
58
+ });
59
+ return map;
60
+ }
61
+ /**
62
+ * Creates a new job via the Lua API and updates the config.
63
+ *
64
+ * @param job - The job to create
65
+ * @param config - The skill configuration
66
+ * @param existingJobs - Array of existing jobs (mutated)
67
+ * @param existingJob - The existing job entry if one exists (may be without ID)
68
+ * @returns The job with its new ID
69
+ */
70
+ async function createJobViaApi(job, config, existingJobs, existingJob) {
71
+ try {
72
+ // Validate prerequisites
73
+ const apiKey = await loadApiKey();
74
+ if (!apiKey) {
75
+ throw new Error("No API key found. Run 'lua auth configure' first.");
76
+ }
77
+ const agentId = config?.agent?.agentId;
78
+ if (!agentId) {
79
+ throw new Error("No agent ID found in lua.skill.yaml. Run 'lua init' first.");
80
+ }
81
+ // Create job via API
82
+ const jobPayload = {
83
+ name: job.name,
84
+ description: job.description || `A Lua job for ${job.name}`,
85
+ context: job.context || '',
86
+ schedule: job.schedule || { type: 'cron', expression: '0 0 * * *' },
87
+ timeout: job.timeout,
88
+ retry: job.retry,
89
+ metadata: job.metadata
90
+ };
91
+ const jobApi = new JobApi(BASE_URLS.API, apiKey, agentId);
92
+ const result = await jobApi.createJob(jobPayload);
93
+ if (result.success && result.data && result.data.id) {
94
+ const newJobId = result.data.id;
95
+ // Update YAML config with new job ID
96
+ if (!existingJob) {
97
+ existingJobs.push({
98
+ name: job.name || '',
99
+ version: job.version || SKILL_DEFAULTS.VERSION,
100
+ jobId: newJobId,
101
+ schedule: job.schedule
102
+ });
103
+ }
104
+ else {
105
+ existingJob.jobId = newJobId;
106
+ existingJob.schedule = job.schedule;
107
+ }
108
+ // Add jobs to config if not already present
109
+ if (!config.jobs) {
110
+ config.jobs = existingJobs;
111
+ }
112
+ return {
113
+ ...job,
114
+ jobId: newJobId
115
+ };
116
+ }
117
+ else {
118
+ console.error(`❌ Failed to create job ${job.name}:`, result.error);
119
+ throw new Error(result.error?.message || 'Failed to create job - no ID returned from API');
120
+ }
121
+ }
122
+ catch (error) {
123
+ console.error(`❌ Failed to create job ${job.name}:`, error);
124
+ throw error;
125
+ }
126
+ }
127
+ /**
128
+ * Updates the lua.skill.yaml file with the current jobs array.
129
+ * Ensures no undefined values are written to the YAML file.
130
+ *
131
+ * @param config - Current skill configuration to merge with
132
+ */
133
+ async function updateYamlWithJobs(config) {
134
+ const jobs = config?.jobs || [];
135
+ // Clean jobs array to ensure no undefined values
136
+ const cleanedJobs = jobs.map(job => ({
137
+ name: job.name || '',
138
+ version: job.version || SKILL_DEFAULTS.VERSION,
139
+ jobId: job.jobId || '',
140
+ schedule: job.schedule || { type: 'cron', expression: '0 0 * * *' }
141
+ }));
142
+ // Update config with cleaned jobs array
143
+ const updatedConfig = {
144
+ ...config,
145
+ jobs: cleanedJobs
146
+ };
147
+ // Write updated YAML with consistent formatting
148
+ const yamlPath = path.join(process.cwd(), COMPILE_FILES.LUA_SKILL_YAML);
149
+ const yamlContent = yaml.dump(updatedConfig, {
150
+ indent: YAML_FORMAT.INDENT,
151
+ lineWidth: YAML_FORMAT.LINE_WIDTH,
152
+ noRefs: YAML_FORMAT.NO_REFS,
153
+ replacer: (key, value) => {
154
+ // Replace undefined values with empty strings
155
+ return value === undefined ? '' : value;
156
+ }
157
+ });
158
+ fs.writeFileSync(yamlPath, yamlContent);
159
+ }
160
+ /**
161
+ * Syncs the server jobs with the YAML configuration.
162
+ * Performs a two-way sync:
163
+ * 1. Deletes/deactivates jobs from server that aren't in YAML
164
+ * 2. Updates YAML with active version numbers from server
165
+ *
166
+ * @param config - The skill configuration from lua.skill.yaml
167
+ * @returns Array of messages about sync operations
168
+ */
169
+ export async function syncServerJobsWithYaml(config) {
170
+ const messages = [];
171
+ let yamlNeedsUpdate = false;
172
+ try {
173
+ // Validate prerequisites
174
+ const apiKey = await loadApiKey();
175
+ if (!apiKey) {
176
+ console.warn("⚠️ No API key found. Skipping server job sync.");
177
+ return messages;
178
+ }
179
+ const agentId = config?.agent?.agentId;
180
+ if (!agentId) {
181
+ console.warn("⚠️ No agent ID found in lua.skill.yaml. Skipping server job sync.");
182
+ return messages;
183
+ }
184
+ // Get jobs from server
185
+ const jobApi = new JobApi(BASE_URLS.API, apiKey, agentId);
186
+ const serverJobsResponse = await jobApi.getJobs();
187
+ if (!serverJobsResponse.success || !serverJobsResponse.data?.jobs) {
188
+ console.warn("⚠️ Could not retrieve server jobs. Skipping server job sync.");
189
+ return messages;
190
+ }
191
+ const serverJobs = serverJobsResponse.data.jobs;
192
+ const yamlJobs = config?.jobs || [];
193
+ // Create maps for efficient lookup
194
+ const yamlJobsMap = new Map(yamlJobs
195
+ .filter((job) => job.jobId)
196
+ .map((job) => [job.jobId, job]));
197
+ const serverJobsMap = new Map(serverJobs.map(job => [job.id, job]));
198
+ // Part 1: Delete jobs from server that aren't in YAML
199
+ const jobsToDelete = serverJobs.filter(serverJob => !yamlJobsMap.has(serverJob.id));
200
+ for (const job of jobsToDelete) {
201
+ try {
202
+ const deleteResponse = await jobApi.deleteJob(job.id);
203
+ if (deleteResponse.success && deleteResponse.data) {
204
+ if (deleteResponse.data.deleted) {
205
+ const msg = `✅ Deleted job "${job.name}" from server`;
206
+ messages.push(msg);
207
+ console.log(msg);
208
+ }
209
+ else if (deleteResponse.data.deactivated) {
210
+ const msg = `⚠️ Job "${job.name}" has versions and cannot be deleted. It has been deactivated instead.`;
211
+ messages.push(msg);
212
+ console.warn(msg);
213
+ }
214
+ }
215
+ else {
216
+ const msg = `❌ Failed to delete job "${job.name}": ${deleteResponse.error?.message || 'Unknown error'}`;
217
+ messages.push(msg);
218
+ console.error(msg);
219
+ }
220
+ }
221
+ catch (error) {
222
+ const msg = `❌ Error deleting job "${job.name}": ${error}`;
223
+ messages.push(msg);
224
+ console.error(msg);
225
+ }
226
+ }
227
+ // Part 2: Sync version numbers from server to YAML
228
+ const updatedYamlJobs = yamlJobs.map((yamlJob) => {
229
+ const serverJob = serverJobsMap.get(yamlJob.jobId);
230
+ if (serverJob && serverJob.versions && serverJob.versions.length > 0) {
231
+ // Find the active version on the server
232
+ const activeVersion = serverJob.versions.find((v) => v.isActive);
233
+ if (activeVersion && activeVersion.version !== yamlJob.version) {
234
+ const msg = `📝 Updated "${yamlJob.name}" job version in YAML: ${yamlJob.version} → ${activeVersion.version}`;
235
+ messages.push(msg);
236
+ console.log(msg);
237
+ yamlNeedsUpdate = true;
238
+ return {
239
+ ...yamlJob,
240
+ version: activeVersion.version,
241
+ schedule: activeVersion.schedule || yamlJob.schedule
242
+ };
243
+ }
244
+ }
245
+ return yamlJob;
246
+ });
247
+ // Update YAML file if versions changed
248
+ if (yamlNeedsUpdate) {
249
+ const updatedConfig = {
250
+ ...config,
251
+ jobs: updatedYamlJobs
252
+ };
253
+ await updateYamlWithJobs(updatedConfig);
254
+ console.log("✅ YAML job versions synced with server");
255
+ }
256
+ if (jobsToDelete.length === 0 && !yamlNeedsUpdate) {
257
+ console.log("✅ Server jobs and YAML are fully in sync");
258
+ }
259
+ }
260
+ catch (error) {
261
+ console.error("❌ Error syncing server jobs:", error);
262
+ }
263
+ return messages;
264
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * PostProcessor Management Utilities
3
+ */
4
+ import { SkillConfig } from '../types/compile.types.js';
5
+ /**
6
+ * Ensures all detected postprocessors exist in the YAML config with valid IDs.
7
+ */
8
+ export declare function ensurePostProcessorsExistInYaml(postprocessorsArray: any[], config: SkillConfig): Promise<any[]>;
9
+ export declare function syncServerPostProcessorsWithYaml(config: SkillConfig): Promise<string[]>;
@@ -0,0 +1,118 @@
1
+ /**
2
+ * PostProcessor Management Utilities
3
+ */
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import yaml from "js-yaml";
7
+ import PostProcessorApi from '../api/postprocessor.api.service.js';
8
+ import { BASE_URLS } from '../config/constants.js';
9
+ import { loadApiKey } from '../services/auth.js';
10
+ import { SKILL_DEFAULTS, YAML_FORMAT } from '../config/compile.constants.js';
11
+ /**
12
+ * Ensures all detected postprocessors exist in the YAML config with valid IDs.
13
+ */
14
+ export async function ensurePostProcessorsExistInYaml(postprocessorsArray, config) {
15
+ const updatedPostProcessorsArray = [];
16
+ let yamlUpdated = false;
17
+ const existingPostProcessors = config?.postprocessors || [];
18
+ const existingMap = new Map(existingPostProcessors.map((p) => [p.name, p]));
19
+ for (const postprocessor of postprocessorsArray) {
20
+ const existing = existingMap.get(postprocessor.name);
21
+ if (existing && existing.postprocessorId) {
22
+ updatedPostProcessorsArray.push({
23
+ ...postprocessor,
24
+ postprocessorId: existing.postprocessorId
25
+ });
26
+ }
27
+ else {
28
+ const created = await createPostProcessorViaApi(postprocessor, config, existingPostProcessors, existing);
29
+ updatedPostProcessorsArray.push(created);
30
+ yamlUpdated = true;
31
+ }
32
+ }
33
+ if (yamlUpdated) {
34
+ await updateYamlWithPostProcessors(config);
35
+ }
36
+ return updatedPostProcessorsArray;
37
+ }
38
+ async function createPostProcessorViaApi(postprocessor, config, existingPostProcessors, existingPostProcessor) {
39
+ try {
40
+ const apiKey = await loadApiKey();
41
+ if (!apiKey)
42
+ throw new Error("No API key found. Run 'lua auth configure' first.");
43
+ const agentId = config?.agent?.agentId;
44
+ if (!agentId)
45
+ throw new Error("No agent ID found in lua.skill.yaml. Run 'lua init' first.");
46
+ const payload = {
47
+ name: postprocessor.name,
48
+ description: postprocessor.description || `A Lua postprocessor for ${postprocessor.name}`,
49
+ context: postprocessor.context || ''
50
+ };
51
+ const api = new PostProcessorApi(BASE_URLS.API, apiKey, agentId);
52
+ const result = await api.createPostProcessor(payload);
53
+ if (result.success && result.data && result.data.id) {
54
+ const newId = result.data.id;
55
+ if (!existingPostProcessor) {
56
+ existingPostProcessors.push({
57
+ name: postprocessor.name || '',
58
+ version: postprocessor.version || SKILL_DEFAULTS.VERSION,
59
+ postprocessorId: newId
60
+ });
61
+ }
62
+ else {
63
+ existingPostProcessor.postprocessorId = newId;
64
+ }
65
+ if (!config.postprocessors) {
66
+ config.postprocessors = existingPostProcessors;
67
+ }
68
+ return {
69
+ ...postprocessor,
70
+ postprocessorId: newId
71
+ };
72
+ }
73
+ else {
74
+ throw new Error(result.error?.message || "Failed to create postprocessor");
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.warn(`Warning: Could not create postprocessor ${postprocessor.name}:`, error);
79
+ return postprocessor;
80
+ }
81
+ }
82
+ async function updateYamlWithPostProcessors(config) {
83
+ const yamlPath = path.join(process.cwd(), 'lua.skill.yaml');
84
+ const yamlContent = yaml.dump(config, { ...YAML_FORMAT, sortKeys: (a, b) => {
85
+ const order = ['agent', 'skills', 'webhooks', 'jobs', 'preprocessors', 'postprocessors', 'skill'];
86
+ const aIndex = order.indexOf(a);
87
+ const bIndex = order.indexOf(b);
88
+ if (aIndex !== -1 && bIndex !== -1)
89
+ return aIndex - bIndex;
90
+ if (aIndex !== -1)
91
+ return -1;
92
+ if (bIndex !== -1)
93
+ return 1;
94
+ return a.localeCompare(b);
95
+ } });
96
+ fs.writeFileSync(yamlPath, yamlContent);
97
+ }
98
+ export async function syncServerPostProcessorsWithYaml(config) {
99
+ const messages = [];
100
+ try {
101
+ const apiKey = await loadApiKey();
102
+ if (!apiKey) {
103
+ console.warn("⚠️ No API key found. Skipping server postprocessor sync.");
104
+ return messages;
105
+ }
106
+ const agentId = config?.agent?.agentId;
107
+ if (!agentId) {
108
+ console.warn("⚠️ No agent ID found. Skipping server postprocessor sync.");
109
+ return messages;
110
+ }
111
+ // Server sync will be implemented when backend is ready
112
+ return messages;
113
+ }
114
+ catch (error) {
115
+ console.warn("⚠️ Error syncing postprocessors:", error);
116
+ return messages;
117
+ }
118
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * PreProcessor Management Utilities
3
+ */
4
+ import { SkillConfig } from '../types/compile.types.js';
5
+ /**
6
+ * Ensures all detected preprocessors exist in the YAML config with valid IDs.
7
+ */
8
+ export declare function ensurePreProcessorsExistInYaml(preprocessorsArray: any[], config: SkillConfig): Promise<any[]>;
9
+ export declare function syncServerPreProcessorsWithYaml(config: SkillConfig): Promise<string[]>;
@@ -0,0 +1,118 @@
1
+ /**
2
+ * PreProcessor Management Utilities
3
+ */
4
+ import fs from "fs";
5
+ import path from "path";
6
+ import yaml from "js-yaml";
7
+ import PreProcessorApi from '../api/preprocessor.api.service.js';
8
+ import { BASE_URLS } from '../config/constants.js';
9
+ import { loadApiKey } from '../services/auth.js';
10
+ import { SKILL_DEFAULTS, YAML_FORMAT } from '../config/compile.constants.js';
11
+ /**
12
+ * Ensures all detected preprocessors exist in the YAML config with valid IDs.
13
+ */
14
+ export async function ensurePreProcessorsExistInYaml(preprocessorsArray, config) {
15
+ const updatedPreProcessorsArray = [];
16
+ let yamlUpdated = false;
17
+ const existingPreProcessors = config?.preprocessors || [];
18
+ const existingMap = new Map(existingPreProcessors.map((p) => [p.name, p]));
19
+ for (const preprocessor of preprocessorsArray) {
20
+ const existing = existingMap.get(preprocessor.name);
21
+ if (existing && existing.preprocessorId) {
22
+ updatedPreProcessorsArray.push({
23
+ ...preprocessor,
24
+ preprocessorId: existing.preprocessorId
25
+ });
26
+ }
27
+ else {
28
+ const created = await createPreProcessorViaApi(preprocessor, config, existingPreProcessors, existing);
29
+ updatedPreProcessorsArray.push(created);
30
+ yamlUpdated = true;
31
+ }
32
+ }
33
+ if (yamlUpdated) {
34
+ await updateYamlWithPreProcessors(config);
35
+ }
36
+ return updatedPreProcessorsArray;
37
+ }
38
+ async function createPreProcessorViaApi(preprocessor, config, existingPreProcessors, existingPreProcessor) {
39
+ try {
40
+ const apiKey = await loadApiKey();
41
+ if (!apiKey)
42
+ throw new Error("No API key found. Run 'lua auth configure' first.");
43
+ const agentId = config?.agent?.agentId;
44
+ if (!agentId)
45
+ throw new Error("No agent ID found in lua.skill.yaml. Run 'lua init' first.");
46
+ const payload = {
47
+ name: preprocessor.name,
48
+ description: preprocessor.description || `A Lua preprocessor for ${preprocessor.name}`,
49
+ context: preprocessor.context || ''
50
+ };
51
+ const api = new PreProcessorApi(BASE_URLS.API, apiKey, agentId);
52
+ const result = await api.createPreProcessor(payload);
53
+ if (result.success && result.data && result.data.id) {
54
+ const newId = result.data.id;
55
+ if (!existingPreProcessor) {
56
+ existingPreProcessors.push({
57
+ name: preprocessor.name || '',
58
+ version: preprocessor.version || SKILL_DEFAULTS.VERSION,
59
+ preprocessorId: newId
60
+ });
61
+ }
62
+ else {
63
+ existingPreProcessor.preprocessorId = newId;
64
+ }
65
+ if (!config.preprocessors) {
66
+ config.preprocessors = existingPreProcessors;
67
+ }
68
+ return {
69
+ ...preprocessor,
70
+ preprocessorId: newId
71
+ };
72
+ }
73
+ else {
74
+ throw new Error(result.error?.message || "Failed to create preprocessor");
75
+ }
76
+ }
77
+ catch (error) {
78
+ console.warn(`Warning: Could not create preprocessor ${preprocessor.name}:`, error);
79
+ return preprocessor;
80
+ }
81
+ }
82
+ async function updateYamlWithPreProcessors(config) {
83
+ const yamlPath = path.join(process.cwd(), 'lua.skill.yaml');
84
+ const yamlContent = yaml.dump(config, { ...YAML_FORMAT, sortKeys: (a, b) => {
85
+ const order = ['agent', 'skills', 'webhooks', 'jobs', 'preprocessors', 'postprocessors', 'skill'];
86
+ const aIndex = order.indexOf(a);
87
+ const bIndex = order.indexOf(b);
88
+ if (aIndex !== -1 && bIndex !== -1)
89
+ return aIndex - bIndex;
90
+ if (aIndex !== -1)
91
+ return -1;
92
+ if (bIndex !== -1)
93
+ return 1;
94
+ return a.localeCompare(b);
95
+ } });
96
+ fs.writeFileSync(yamlPath, yamlContent);
97
+ }
98
+ export async function syncServerPreProcessorsWithYaml(config) {
99
+ const messages = [];
100
+ try {
101
+ const apiKey = await loadApiKey();
102
+ if (!apiKey) {
103
+ console.warn("⚠️ No API key found. Skipping server preprocessor sync.");
104
+ return messages;
105
+ }
106
+ const agentId = config?.agent?.agentId;
107
+ if (!agentId) {
108
+ console.warn("⚠️ No agent ID found. Skipping server preprocessor sync.");
109
+ return messages;
110
+ }
111
+ // Server sync will be implemented when backend is ready
112
+ return messages;
113
+ }
114
+ catch (error) {
115
+ console.warn("⚠️ Error syncing preprocessors:", error);
116
+ return messages;
117
+ }
118
+ }