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
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Sync Helpers
3
+ * Utilities for detecting drift between server state and local code
4
+ */
5
+ import { diffLines } from 'diff';
6
+ import { BASE_URLS } from '../config/constants.js';
7
+ import { loadPersonaFromCode, loadNameFromCode } from './agent-code-utils.js';
8
+ import PersonaApi from '../api/persona.api.service.js';
9
+ import AgentApi from '../api/agent.api.service.js';
10
+ // ANSI color codes
11
+ const colors = {
12
+ red: '\x1b[31m',
13
+ green: '\x1b[32m',
14
+ gray: '\x1b[90m',
15
+ reset: '\x1b[0m',
16
+ bold: '\x1b[1m',
17
+ };
18
+ /**
19
+ * Fetch the latest published persona version from the server.
20
+ * Returns null if no persona is published or on error.
21
+ *
22
+ * Note: This returns the most recently published version, NOT the current/active one.
23
+ * The current version might be an older rollback, but code should match the latest push.
24
+ * Drafts are excluded since they haven't been deployed yet.
25
+ */
26
+ export async function fetchServerPersona(apiKey, agentId) {
27
+ try {
28
+ const personaApi = new PersonaApi(BASE_URLS.API, apiKey, agentId);
29
+ const latestPublished = await personaApi.getLatestPublishedVersion();
30
+ if (latestPublished && latestPublished.persona) {
31
+ return {
32
+ persona: latestPublished.persona,
33
+ version: latestPublished.version,
34
+ };
35
+ }
36
+ return null;
37
+ }
38
+ catch (error) {
39
+ // Silently fail - network issues shouldn't block compilation
40
+ return null;
41
+ }
42
+ }
43
+ /**
44
+ * Compare server persona with local persona.
45
+ * Returns true if they differ (drift detected).
46
+ */
47
+ export function comparePersona(serverPersona, localPersona) {
48
+ if (serverPersona === null) {
49
+ return false; // No server state to compare against
50
+ }
51
+ // Normalize whitespace for comparison
52
+ const normalizedServer = serverPersona.trim();
53
+ const normalizedLocal = localPersona.trim();
54
+ return normalizedServer !== normalizedLocal;
55
+ }
56
+ /**
57
+ * Check for persona drift between server and local code.
58
+ * Returns drift info if drift detected, null otherwise.
59
+ */
60
+ export async function checkPersonaDrift(apiKey, agentId) {
61
+ const localPersona = loadPersonaFromCode();
62
+ const serverData = await fetchServerPersona(apiKey, agentId);
63
+ const hasDrift = comparePersona(serverData?.persona || null, localPersona);
64
+ if (!hasDrift) {
65
+ return null;
66
+ }
67
+ return {
68
+ hasDrift: true,
69
+ serverPersona: serverData?.persona || null,
70
+ localPersona,
71
+ serverVersion: serverData?.version,
72
+ };
73
+ }
74
+ /**
75
+ * Display a colored diff between two strings.
76
+ */
77
+ export function showColoredDiff(oldText, newText, oldLabel = 'Server', newLabel = 'Local') {
78
+ if (!oldText && !newText) {
79
+ console.log(colors.gray + '(both empty)' + colors.reset);
80
+ return;
81
+ }
82
+ if (!oldText) {
83
+ console.log(colors.green + `+ (${newLabel} only - no ${oldLabel} content)` + colors.reset);
84
+ return;
85
+ }
86
+ if (!newText) {
87
+ console.log(colors.red + `- (${oldLabel} only - no ${newLabel} content)` + colors.reset);
88
+ return;
89
+ }
90
+ const diff = diffLines(oldText, newText);
91
+ diff.forEach(part => {
92
+ if (part.added) {
93
+ // Added in local (green)
94
+ const lines = part.value.split('\n').filter(l => l);
95
+ lines.forEach(line => {
96
+ console.log(colors.green + '+ ' + line + colors.reset);
97
+ });
98
+ }
99
+ else if (part.removed) {
100
+ // Removed from server (red)
101
+ const lines = part.value.split('\n').filter(l => l);
102
+ lines.forEach(line => {
103
+ console.log(colors.red + '- ' + line + colors.reset);
104
+ });
105
+ }
106
+ else {
107
+ // Unchanged - show abbreviated context
108
+ const lines = part.value.split('\n').filter(l => l);
109
+ if (lines.length <= 6) {
110
+ lines.forEach(line => {
111
+ console.log(colors.gray + ' ' + line + colors.reset);
112
+ });
113
+ }
114
+ else {
115
+ // Show first 3 and last 3 lines
116
+ lines.slice(0, 3).forEach(line => {
117
+ console.log(colors.gray + ' ' + line + colors.reset);
118
+ });
119
+ console.log(colors.gray + ` ... (${lines.length - 6} unchanged lines) ...` + colors.reset);
120
+ lines.slice(-3).forEach(line => {
121
+ console.log(colors.gray + ' ' + line + colors.reset);
122
+ });
123
+ }
124
+ }
125
+ });
126
+ }
127
+ /**
128
+ * Display a diff between server and local persona.
129
+ */
130
+ export function showPersonaDiff(serverPersona, localPersona) {
131
+ console.log('\n' + '='.repeat(60));
132
+ console.log(colors.bold + 'PERSONA DIFF' + colors.reset);
133
+ console.log(colors.red + '- Server (deployed)' + colors.reset + ' ' + colors.green + '+ Local (code)' + colors.reset);
134
+ console.log('='.repeat(60) + '\n');
135
+ showColoredDiff(serverPersona || '', localPersona, 'Server', 'Local');
136
+ console.log('\n' + '='.repeat(60) + '\n');
137
+ }
138
+ /**
139
+ * Display a compact drift warning for compile flow.
140
+ */
141
+ export function showDriftWarning(drift) {
142
+ console.log('\n⚠️ Persona drift detected!');
143
+ console.log(` Server version ${drift.serverVersion || 'unknown'} differs from local code.`);
144
+ }
145
+ /**
146
+ * Fetch the agent name from the server.
147
+ */
148
+ export async function fetchServerName(apiKey, agentId) {
149
+ try {
150
+ const agentApi = new AgentApi(BASE_URLS.API, apiKey);
151
+ const response = await agentApi.getAgent(agentId);
152
+ if (response.success && response.data?.name) {
153
+ return response.data.name;
154
+ }
155
+ return null;
156
+ }
157
+ catch (error) {
158
+ return null;
159
+ }
160
+ }
161
+ /**
162
+ * Check for name drift between server and local code.
163
+ */
164
+ export async function checkNameDrift(apiKey, agentId) {
165
+ const localName = loadNameFromCode();
166
+ const serverName = await fetchServerName(apiKey, agentId);
167
+ if (serverName === null) {
168
+ return null; // No server state to compare against
169
+ }
170
+ const hasDrift = serverName.trim() !== localName.trim();
171
+ if (!hasDrift) {
172
+ return null;
173
+ }
174
+ return {
175
+ hasDrift: true,
176
+ serverName,
177
+ localName,
178
+ };
179
+ }
180
+ /**
181
+ * Display name drift info.
182
+ */
183
+ export function showNameDiff(serverName, localName) {
184
+ console.log('\n' + '='.repeat(60));
185
+ console.log(colors.bold + 'NAME DIFF' + colors.reset);
186
+ console.log('='.repeat(60));
187
+ console.log(colors.red + `- Server: "${serverName || '(none)'}"` + colors.reset);
188
+ console.log(colors.green + `+ Local: "${localName || '(none)'}"` + colors.reset);
189
+ console.log('='.repeat(60) + '\n');
190
+ }
@@ -31,10 +31,3 @@ export declare function extractToolsFromDeployData(deployData: any): ToolData[];
31
31
  * @returns True if .env file exists
32
32
  */
33
33
  export declare function hasEnvFile(): boolean;
34
- /**
35
- * Checks if config has environment variables defined.
36
- *
37
- * @param config - Skill configuration
38
- * @returns True if config has environment variables
39
- */
40
- export declare function hasConfigEnvVars(config: any): boolean;
@@ -81,12 +81,3 @@ export function extractToolsFromDeployData(deployData) {
81
81
  export function hasEnvFile() {
82
82
  return fs.existsSync(path.join(process.cwd(), '.env'));
83
83
  }
84
- /**
85
- * Checks if config has environment variables defined.
86
- *
87
- * @param config - Skill configuration
88
- * @returns True if config has environment variables
89
- */
90
- export function hasConfigEnvVars(config) {
91
- return config?.skill?.env && Object.keys(config.skill.env).length > 0;
92
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lua-cli",
3
- "version": "3.1.0",
3
+ "version": "3.2.0-alpha.1",
4
4
  "description": "Build, test, and deploy AI agents with custom tools, webhooks, and scheduled jobs. Features LuaAgent unified configuration, streaming chat, and batch deployment.",
5
5
  "readmeFilename": "README.md",
6
6
  "main": "dist/api-exports.js",
@@ -67,6 +67,7 @@
67
67
  "autoprefixer": "^10.4.21",
68
68
  "chalk": "^5.3.0",
69
69
  "commander": "^14.0.1",
70
+ "diff": "^8.0.2",
70
71
  "dotenv": "^17.2.3",
71
72
  "esbuild": "^0.25.10",
72
73
  "inquirer": "^12.9.6",
@@ -84,6 +85,7 @@
84
85
  "zod-to-json-schema": "^3.24.6"
85
86
  },
86
87
  "devDependencies": {
88
+ "@types/diff": "^7.0.2",
87
89
  "@types/inquirer": "^9.0.9",
88
90
  "@types/jest": "^29.5.8",
89
91
  "@types/js-yaml": "^4.0.9",
@@ -21,7 +21,7 @@ lua push all --force --auto-deploy
21
21
  your-project/
22
22
  ├── src/
23
23
  │ └── index.ts # Your agent configuration
24
- ├── lua.skill.yaml # Agent metadata (auto-managed)
24
+ ├── lua.skill.yaml # State manifest (IDs + versions only; auto-managed)
25
25
  ├── package.json # Dependencies
26
26
  └── tsconfig.json # TypeScript config
27
27
  ```
@@ -1 +1,11 @@
1
+ agent:
2
+ agentId: ""
3
+ orgId: ""
4
+
5
+ # State-only manifest (managed by the CLI)
1
6
  skills: []
7
+ webhooks: []
8
+ jobs: []
9
+ preprocessors: []
10
+ postprocessors: []
11
+ mcpServers: []
@@ -20,7 +20,7 @@
20
20
  "inquirer": "^12.9.6",
21
21
  "stripe": "^17.5.0",
22
22
  "js-yaml": "^4.1.0",
23
- "lua-cli": "^3.1.0",
23
+ "lua-cli": "^3.2.0-alpha.1",
24
24
  "openai": "^5.23.0",
25
25
  "uuid": "^13.0.0",
26
26
  "zod": "^3.24.1"
@@ -1,23 +0,0 @@
1
- /**
2
- * Agent Management Utilities
3
- * Handles LuaAgent persona synchronization with lua.skill.yaml
4
- */
5
- /**
6
- * Syncs the agent's name and persona with lua.skill.yaml.
7
- * This ensures the YAML configuration reflects the agent definition in code.
8
- *
9
- * @param agentMetadata - Agent metadata extracted from LuaAgent
10
- */
11
- export declare function syncAgentPersonaWithYaml(agentMetadata: {
12
- name: string;
13
- persona: string;
14
- }): Promise<void>;
15
- /**
16
- * Reads the agent persona from lua.skill.yaml.
17
- * This can be used to ensure the code and YAML are in sync.
18
- *
19
- * @returns Agent persona from YAML, or null if not found
20
- */
21
- export declare function readAgentPersonaFromYaml(): {
22
- persona?: string;
23
- } | null;
@@ -1,67 +0,0 @@
1
- /**
2
- * Agent Management Utilities
3
- * Handles LuaAgent persona synchronization with lua.skill.yaml
4
- */
5
- import fs from "fs";
6
- import path from "path";
7
- import yaml from "js-yaml";
8
- import { COMPILE_FILES, YAML_FORMAT } from '../config/compile.constants.js';
9
- /**
10
- * Syncs the agent's name and persona with lua.skill.yaml.
11
- * This ensures the YAML configuration reflects the agent definition in code.
12
- *
13
- * @param agentMetadata - Agent metadata extracted from LuaAgent
14
- */
15
- export async function syncAgentPersonaWithYaml(agentMetadata) {
16
- const yamlPath = path.join(process.cwd(), COMPILE_FILES.LUA_SKILL_YAML);
17
- // Read existing YAML config
18
- let config = {};
19
- if (fs.existsSync(yamlPath)) {
20
- const yamlContent = fs.readFileSync(yamlPath, 'utf8');
21
- config = yaml.load(yamlContent);
22
- }
23
- // Update agent section with persona
24
- config.agent = {
25
- ...config.agent,
26
- persona: agentMetadata.persona
27
- };
28
- // Store agent name as a comment or in metadata (YAML doesn't have an agentName field)
29
- // The agent name is primarily for the LuaAgent in code
30
- // Write updated YAML with consistent formatting
31
- const yamlContent = yaml.dump(config, {
32
- indent: YAML_FORMAT.INDENT,
33
- lineWidth: YAML_FORMAT.LINE_WIDTH,
34
- noRefs: YAML_FORMAT.NO_REFS,
35
- replacer: (key, value) => {
36
- // Replace undefined values with empty strings
37
- return value === undefined ? '' : value;
38
- }
39
- });
40
- fs.writeFileSync(yamlPath, yamlContent);
41
- console.log(`✅ Synced agent configuration to lua.skill.yaml`);
42
- }
43
- /**
44
- * Reads the agent persona from lua.skill.yaml.
45
- * This can be used to ensure the code and YAML are in sync.
46
- *
47
- * @returns Agent persona from YAML, or null if not found
48
- */
49
- export function readAgentPersonaFromYaml() {
50
- const yamlPath = path.join(process.cwd(), COMPILE_FILES.LUA_SKILL_YAML);
51
- if (!fs.existsSync(yamlPath)) {
52
- return null;
53
- }
54
- try {
55
- const yamlContent = fs.readFileSync(yamlPath, 'utf8');
56
- const config = yaml.load(yamlContent);
57
- if (config.agent) {
58
- return {
59
- persona: config.agent.persona
60
- };
61
- }
62
- }
63
- catch (error) {
64
- console.warn(`Warning: Could not read agent persona from lua.skill.yaml: ${error}`);
65
- }
66
- return null;
67
- }