@agentlang/cli 0.11.9 → 0.12.0
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.
- package/out/main.js +206 -268
- package/out/main.js.map +1 -1
- package/out/repl.js +86 -100
- package/out/repl.js.map +1 -1
- package/out/studio/services/AppManagementService.js +7 -19
- package/out/studio/services/AppManagementService.js.map +1 -1
- package/out/studio/services/AppRuntimeService.js +14 -15
- package/out/studio/services/AppRuntimeService.js.map +1 -1
- package/out/studio/services/GitHubService.js +16 -16
- package/out/studio/services/GitHubService.js.map +1 -1
- package/out/studio.js +36 -41
- package/out/studio.js.map +1 -1
- package/out/ui/components/Help.js +25 -0
- package/out/ui/components/Help.js.map +1 -0
- package/out/ui/index.js +2 -0
- package/out/ui/index.js.map +1 -0
- package/out/ui/print.js +61 -0
- package/out/ui/print.js.map +1 -0
- package/out/ui-generator/specFinder.js +4 -7
- package/out/ui-generator/specFinder.js.map +1 -1
- package/out/ui-generator/specLoader.js +2 -3
- package/out/ui-generator/specLoader.js.map +1 -1
- package/out/ui-generator/uiGenerator.js +56 -57
- package/out/ui-generator/uiGenerator.js.map +1 -1
- package/out/utils/projectInitializer.js +21 -58
- package/out/utils/projectInitializer.js.map +1 -1
- package/package.json +6 -4
package/out/main.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
1
|
import { Command } from 'commander';
|
|
3
2
|
import { NodeFileSystem } from 'langium/node';
|
|
4
3
|
import * as path from 'node:path';
|
|
@@ -9,6 +8,10 @@ import { initializeProject } from './utils/projectInitializer.js';
|
|
|
9
8
|
import { existsSync, readFileSync } from 'node:fs';
|
|
10
9
|
import { fileURLToPath } from 'node:url';
|
|
11
10
|
import { dirname, join } from 'node:path';
|
|
11
|
+
import { renderToString } from 'ink';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import Help from './ui/components/Help.js';
|
|
14
|
+
import { ui, ansi } from './ui/index.js';
|
|
12
15
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
16
|
const __dirname = dirname(__filename);
|
|
14
17
|
let agPath = 'agentlang';
|
|
@@ -58,8 +61,7 @@ function getDefaultRepoUrl(appName) {
|
|
|
58
61
|
}
|
|
59
62
|
async function promptAndPushRepository(git, appName) {
|
|
60
63
|
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
61
|
-
|
|
62
|
-
console.log(chalk.dim('Skipping git push prompt (non-interactive terminal).'));
|
|
64
|
+
ui.dim('Skipping git push prompt (non-interactive terminal).');
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
const rl = createInterface({
|
|
@@ -67,14 +69,14 @@ async function promptAndPushRepository(git, appName) {
|
|
|
67
69
|
output: process.stdout,
|
|
68
70
|
});
|
|
69
71
|
try {
|
|
70
|
-
const pushAnswer = (await rl.question(
|
|
72
|
+
const pushAnswer = (await rl.question(ansi.cyan('Would you like to push this repo now? (y/N) ')))
|
|
71
73
|
.trim()
|
|
72
74
|
.toLowerCase();
|
|
73
75
|
if (pushAnswer !== 'y' && pushAnswer !== 'yes') {
|
|
74
76
|
return;
|
|
75
77
|
}
|
|
76
78
|
const defaultRepoUrl = getDefaultRepoUrl(appName);
|
|
77
|
-
const repoUrlInputPromise = rl.question(
|
|
79
|
+
const repoUrlInputPromise = rl.question(ansi.cyan('Repository URL: '));
|
|
78
80
|
rl.write(defaultRepoUrl);
|
|
79
81
|
const repoUrlInput = await repoUrlInputPromise;
|
|
80
82
|
const repoUrl = repoUrlInput.trim() || defaultRepoUrl;
|
|
@@ -88,12 +90,10 @@ async function promptAndPushRepository(git, appName) {
|
|
|
88
90
|
}
|
|
89
91
|
const currentBranch = (await git.branch()).current || 'main';
|
|
90
92
|
await git.push(['-u', 'origin', currentBranch]);
|
|
91
|
-
|
|
92
|
-
console.log(`${chalk.green('✓')} Pushed to ${chalk.cyan(repoUrl)}`);
|
|
93
|
+
ui.step('✓', 'Pushed to', repoUrl);
|
|
93
94
|
}
|
|
94
95
|
catch (error) {
|
|
95
|
-
|
|
96
|
-
console.log(chalk.yellow(`⚠️ Skipped pushing repository: ${error instanceof Error ? error.message : String(error)}`));
|
|
96
|
+
ui.warn(`Skipped pushing repository: ${error instanceof Error ? error.message : String(error)}`);
|
|
97
97
|
}
|
|
98
98
|
finally {
|
|
99
99
|
rl.close();
|
|
@@ -103,33 +103,41 @@ async function promptAndPushRepository(git, appName) {
|
|
|
103
103
|
export const initCommand = async (appName, options) => {
|
|
104
104
|
const currentDir = process.cwd();
|
|
105
105
|
const targetDir = join(currentDir, appName);
|
|
106
|
+
ui.blank();
|
|
107
|
+
ui.banner('Initialize App');
|
|
108
|
+
ui.blank();
|
|
109
|
+
ui.label('App', appName, 'cyan');
|
|
110
|
+
ui.label('Location', targetDir);
|
|
111
|
+
ui.blank();
|
|
106
112
|
try {
|
|
107
113
|
await initializeProject(targetDir, appName, {
|
|
108
114
|
prompt: options === null || options === void 0 ? void 0 : options.prompt,
|
|
109
|
-
silent: false,
|
|
115
|
+
silent: false,
|
|
110
116
|
});
|
|
111
|
-
// Change to the app directory (for CLI context)
|
|
112
117
|
try {
|
|
113
118
|
process.chdir(targetDir);
|
|
114
|
-
// eslint-disable-next-line no-console
|
|
115
|
-
console.log(chalk.cyan(`\n📂 Changed directory to ${chalk.bold(appName)}`));
|
|
116
119
|
}
|
|
117
120
|
catch (_a) {
|
|
118
121
|
// Ignore if can't change directory
|
|
119
122
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
ui.blank();
|
|
124
|
+
ui.divider(50);
|
|
125
|
+
ui.success(`${appName} initialized successfully!`);
|
|
126
|
+
ui.blank();
|
|
127
|
+
ui.dim('Next steps:');
|
|
128
|
+
ui.dim(' 1. Add your application logic to src/core.al');
|
|
129
|
+
ui.row([
|
|
130
|
+
{ text: ' 2. Run your app with: ', dimColor: true },
|
|
131
|
+
{ text: 'agent run', color: 'cyan' },
|
|
132
|
+
]);
|
|
133
|
+
ui.row([
|
|
134
|
+
{ text: ' 3. Or start Studio UI with: ', dimColor: true },
|
|
135
|
+
{ text: 'agent studio', color: 'cyan' },
|
|
136
|
+
]);
|
|
137
|
+
ui.divider(50);
|
|
138
|
+
ui.blank();
|
|
130
139
|
// Handle interactive git push
|
|
131
140
|
const git = simpleGit(targetDir);
|
|
132
|
-
// Check if git is initialized (initializeProject does it, but let's be safe)
|
|
133
141
|
if (await git.checkIsRepo()) {
|
|
134
142
|
await promptAndPushRepository(git, appName);
|
|
135
143
|
}
|
|
@@ -138,121 +146,36 @@ export const initCommand = async (appName, options) => {
|
|
|
138
146
|
}
|
|
139
147
|
}
|
|
140
148
|
catch (error) {
|
|
141
|
-
|
|
142
|
-
console.error(chalk.red('❌ Error initializing application:'), error instanceof Error ? error.message : error);
|
|
149
|
+
ui.error(`Error initializing application: ${error instanceof Error ? error.message : String(error)}`);
|
|
143
150
|
process.exit(1);
|
|
144
151
|
}
|
|
145
152
|
};
|
|
146
|
-
// Custom help formatter
|
|
147
|
-
function customHelp() {
|
|
148
|
-
const gradient = [chalk.hex('#00D9FF'), chalk.hex('#00C4E6'), chalk.hex('#00AFCC'), chalk.hex('#009AB3')];
|
|
149
|
-
const header = `
|
|
150
|
-
${gradient[0]('█████╗')} ${gradient[1](' ██████╗')} ${gradient[2]('███████╗')}${gradient[3]('███╗ ██╗')}${gradient[0]('████████╗')}
|
|
151
|
-
${gradient[0]('██╔══██╗')}${gradient[1]('██╔════╝')} ${gradient[2]('██╔════╝')}${gradient[3]('████╗ ██║')}${gradient[0]('╚══██╔══╝')}
|
|
152
|
-
${gradient[0]('███████║')}${gradient[1]('██║ ███╗')}${gradient[2]('█████╗')} ${gradient[3]('██╔██╗ ██║')}${gradient[0](' ██║')}
|
|
153
|
-
${gradient[0]('██╔══██║')}${gradient[1]('██║ ██║')}${gradient[2]('██╔══╝')} ${gradient[3]('██║╚██╗██║')}${gradient[0](' ██║')}
|
|
154
|
-
${gradient[0]('██║ ██║')}${gradient[1]('╚██████╔╝')}${gradient[2]('███████╗')}${gradient[3]('██║ ╚████║')}${gradient[0](' ██║')}
|
|
155
|
-
${gradient[0]('╚═╝ ╚═╝')} ${gradient[1]('╚═════╝')} ${gradient[2]('╚══════╝')}${gradient[3]('╚═╝ ╚═══╝')}${gradient[0](' ╚═╝')}
|
|
156
|
-
|
|
157
|
-
${chalk.bold.white('Agentlang CLI')} ${chalk.dim(`v${packageVersion}`)}
|
|
158
|
-
${chalk.dim('CLI for all things Agentlang')}
|
|
159
|
-
`;
|
|
160
|
-
const usage = `
|
|
161
|
-
${chalk.bold.white('USAGE')}
|
|
162
|
-
${chalk.dim('$')} ${chalk.cyan('agent')} ${chalk.yellow('<command>')} ${chalk.dim('[options]')}
|
|
163
|
-
|
|
164
|
-
${chalk.bold.white('COMMANDS')}
|
|
165
|
-
|
|
166
|
-
${chalk.cyan.bold('init')} ${chalk.dim('<appname>')}
|
|
167
|
-
${chalk.white('▸')} Initialize a new Agentlang application
|
|
168
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
169
|
-
${chalk.yellow('OPTIONS')}
|
|
170
|
-
${chalk.cyan('-p, --prompt')} ${chalk.dim('<description>')} Description or prompt for the application
|
|
171
|
-
|
|
172
|
-
${chalk.cyan.bold('run')} ${chalk.dim('[file]')}
|
|
173
|
-
${chalk.white('▸')} Load and execute an Agentlang module
|
|
174
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
175
|
-
${chalk.yellow('OPTIONS')}
|
|
176
|
-
${chalk.cyan('-c, --config')} ${chalk.dim('<file>')} Configuration file path
|
|
177
|
-
|
|
178
|
-
${chalk.cyan.bold('repl')} ${chalk.dim('[directory]')}
|
|
179
|
-
${chalk.white('▸')} Start interactive REPL environment
|
|
180
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
181
|
-
${chalk.yellow('OPTIONS')}
|
|
182
|
-
${chalk.cyan('-w, --watch')} Watch files and reload automatically
|
|
183
|
-
${chalk.cyan('-q, --quiet')} Suppress startup messages
|
|
184
|
-
|
|
185
|
-
${chalk.cyan.bold('doc')} ${chalk.dim('[file]')}
|
|
186
|
-
${chalk.white('▸')} Generate API documentation (Swagger/OpenAPI)
|
|
187
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
188
|
-
${chalk.yellow('OPTIONS')}
|
|
189
|
-
${chalk.cyan('-h, --outputHtml')} ${chalk.dim('<file>')} Generate HTML documentation
|
|
190
|
-
${chalk.cyan('-p, --outputPostman')} ${chalk.dim('<file>')} Generate Postman collection
|
|
191
|
-
|
|
192
|
-
${chalk.cyan.bold('parseAndValidate')} ${chalk.dim('<file>')}
|
|
193
|
-
${chalk.white('▸')} Parse and validate Agentlang source code
|
|
194
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
195
|
-
${chalk.yellow('OPTIONS')}
|
|
196
|
-
${chalk.cyan('-d, --destination')} ${chalk.dim('<dir>')} Output directory
|
|
197
|
-
|
|
198
|
-
${chalk.cyan.bold('ui-gen')} ${chalk.dim('[spec-file]')}
|
|
199
|
-
${chalk.white('▸')} Generate UI from specification ${chalk.dim('(requires Anthropic API key)')}
|
|
200
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
201
|
-
${chalk.yellow('OPTIONS')}
|
|
202
|
-
${chalk.cyan('-d, --directory')} ${chalk.dim('<dir>')} Target directory
|
|
203
|
-
${chalk.cyan('-k, --api-key')} ${chalk.dim('<key>')} Anthropic API key
|
|
204
|
-
${chalk.cyan('-p, --push')} Commit and push to git
|
|
205
|
-
${chalk.cyan('-m, --message')} ${chalk.dim('<text>')} Update instructions
|
|
206
|
-
|
|
207
|
-
${chalk.cyan.bold('fork')} ${chalk.dim('<source> [name]')}
|
|
208
|
-
${chalk.white('▸')} Fork an app from a local directory or git repository
|
|
209
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
210
|
-
${chalk.yellow('OPTIONS')}
|
|
211
|
-
${chalk.cyan('-b, --branch')} ${chalk.dim('<branch>')} Git branch to clone (for git URLs)
|
|
212
|
-
${chalk.cyan('-u, --username')} ${chalk.dim('<username>')} GitHub username for authenticated access
|
|
213
|
-
${chalk.cyan('-t, --token')} ${chalk.dim('<token>')} GitHub token for authenticated access
|
|
214
|
-
|
|
215
|
-
${chalk.cyan.bold('import')} ${chalk.dim('<source> [name]')}
|
|
216
|
-
${chalk.white('▸')} Import an app (alias for fork)
|
|
217
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
218
|
-
${chalk.yellow('OPTIONS')}
|
|
219
|
-
${chalk.cyan('-b, --branch')} ${chalk.dim('<branch>')} Git branch to clone (for git URLs)
|
|
220
|
-
${chalk.cyan('-u, --username')} ${chalk.dim('<username>')} GitHub username for authenticated access
|
|
221
|
-
${chalk.cyan('-t, --token')} ${chalk.dim('<token>')} GitHub token for authenticated access
|
|
222
|
-
|
|
223
|
-
${chalk.cyan.bold('studio')} ${chalk.dim('[path]')}
|
|
224
|
-
${chalk.white('▸')} Start Agentlang Studio with local server
|
|
225
|
-
${chalk.dim('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━')}
|
|
226
|
-
${chalk.yellow('OPTIONS')}
|
|
227
|
-
${chalk.cyan('-p, --port')} ${chalk.dim('<port>')} Port to run Studio server on (default: 4000)
|
|
228
|
-
|
|
229
|
-
${chalk.bold.white('GLOBAL OPTIONS')}
|
|
230
|
-
${chalk.cyan('-h, --help')} Display help information
|
|
231
|
-
${chalk.cyan('-V, --version')} Display version number
|
|
232
|
-
|
|
233
|
-
${chalk.bold.white('LEARN MORE')}
|
|
234
|
-
${chalk.white('Docs')} ${chalk.cyan('https://github.com/agentlang/agentlang-cli')}
|
|
235
|
-
${chalk.white('Issues')} ${chalk.cyan('https://github.com/agentlang/agentlang-cli/issues')}
|
|
236
|
-
|
|
237
|
-
${chalk.dim('Run')} ${chalk.cyan('agent <command> --help')} ${chalk.dim('for detailed command information')}
|
|
238
|
-
`;
|
|
239
|
-
return header + usage;
|
|
240
|
-
}
|
|
241
153
|
export default function () {
|
|
242
154
|
const program = new Command();
|
|
243
155
|
// Configure program
|
|
244
156
|
program
|
|
245
157
|
.name('agent')
|
|
246
|
-
.description(
|
|
158
|
+
.description('CLI for all things Agentlang')
|
|
247
159
|
.version(packageVersion, '-V, --version', 'Display version number')
|
|
248
|
-
.helpOption(
|
|
160
|
+
.helpOption(false)
|
|
249
161
|
.helpCommand(false)
|
|
250
162
|
.configureHelp({
|
|
251
163
|
sortSubcommands: true,
|
|
252
164
|
sortOptions: true,
|
|
253
165
|
});
|
|
254
|
-
//
|
|
255
|
-
program.helpInformation =
|
|
166
|
+
// Use ink-rendered help via renderToString
|
|
167
|
+
program.helpInformation = () => {
|
|
168
|
+
return renderToString(React.createElement(Help, { version: packageVersion }), {
|
|
169
|
+
columns: process.stdout.columns || 80,
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
// Add explicit help flag since we disabled the built-in one
|
|
173
|
+
program.option('-h, --help', 'Show help information');
|
|
174
|
+
program.on('option:help', () => {
|
|
175
|
+
// eslint-disable-next-line no-console
|
|
176
|
+
console.log(program.helpInformation());
|
|
177
|
+
process.exit(0);
|
|
178
|
+
});
|
|
256
179
|
const fileExtensions = AgentlangLanguageMetaData.fileExtensions.join(', ');
|
|
257
180
|
program
|
|
258
181
|
.command('init')
|
|
@@ -260,7 +183,7 @@ export default function () {
|
|
|
260
183
|
.option('-p, --prompt <description>', 'Description or prompt for the application')
|
|
261
184
|
.description('Initialize a new Agentlang application')
|
|
262
185
|
.addHelpText('after', `
|
|
263
|
-
${
|
|
186
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
264
187
|
Creates a new Agentlang application with the necessary project structure.
|
|
265
188
|
This command will create:
|
|
266
189
|
• package.json with your app name and version
|
|
@@ -270,18 +193,18 @@ ${chalk.bold.white('DESCRIPTION')}
|
|
|
270
193
|
The command checks if the directory is already initialized by looking for
|
|
271
194
|
existing package.json or .al files (excluding config.al).
|
|
272
195
|
|
|
273
|
-
${
|
|
274
|
-
${
|
|
275
|
-
${
|
|
196
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
197
|
+
${ui.format.dim('Initialize a new app called CarDealership')}
|
|
198
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent init CarDealership')}
|
|
276
199
|
|
|
277
|
-
${
|
|
278
|
-
${
|
|
200
|
+
${ui.format.dim('Initialize a new e-commerce app')}
|
|
201
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent init MyShop')}
|
|
279
202
|
|
|
280
|
-
${
|
|
281
|
-
${
|
|
203
|
+
${ui.format.dim('Initialize with multiple words (use PascalCase)')}
|
|
204
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent init InventoryManagement')}
|
|
282
205
|
|
|
283
|
-
${
|
|
284
|
-
${
|
|
206
|
+
${ui.format.dim('Initialize with a description/prompt')}
|
|
207
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent init ShowroomApp --prompt "a showroom app"')}
|
|
285
208
|
`)
|
|
286
209
|
.action(initCommand);
|
|
287
210
|
program
|
|
@@ -290,22 +213,22 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
290
213
|
.option('-c, --config <config>', 'Path to configuration file')
|
|
291
214
|
.description('Load and execute an Agentlang module')
|
|
292
215
|
.addHelpText('after', `
|
|
293
|
-
${
|
|
216
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
294
217
|
Loads and executes an Agentlang module, starting the runtime environment
|
|
295
218
|
and initializing all configured services, databases, and integrations.
|
|
296
219
|
|
|
297
|
-
${
|
|
298
|
-
${
|
|
299
|
-
${
|
|
220
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
221
|
+
${ui.format.dim('Run module in current directory')}
|
|
222
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent run')}
|
|
300
223
|
|
|
301
|
-
${
|
|
302
|
-
${
|
|
224
|
+
${ui.format.dim('Run specific module file')}
|
|
225
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent run ./my-app/main.al')}
|
|
303
226
|
|
|
304
|
-
${
|
|
305
|
-
${
|
|
227
|
+
${ui.format.dim('Run with custom configuration')}
|
|
228
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent run ./my-app -c config.json')}
|
|
306
229
|
|
|
307
|
-
${
|
|
308
|
-
${
|
|
230
|
+
${ui.format.dim('Run module from specific directory')}
|
|
231
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent run ~/projects/erp-system')}
|
|
309
232
|
`)
|
|
310
233
|
.action(runModule);
|
|
311
234
|
program
|
|
@@ -315,26 +238,26 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
315
238
|
.option('-q, --quiet', 'Suppress startup messages')
|
|
316
239
|
.description('Start interactive REPL environment')
|
|
317
240
|
.addHelpText('after', `
|
|
318
|
-
${
|
|
241
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
319
242
|
Starts an interactive Read-Eval-Print Loop (REPL) environment for
|
|
320
243
|
Agentlang, allowing you to execute code interactively, test functions,
|
|
321
244
|
and explore your application in real-time.
|
|
322
245
|
|
|
323
|
-
${
|
|
324
|
-
${
|
|
325
|
-
${
|
|
246
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
247
|
+
${ui.format.dim('Start REPL in current directory')}
|
|
248
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent repl')}
|
|
326
249
|
|
|
327
|
-
${
|
|
328
|
-
${
|
|
250
|
+
${ui.format.dim('Start REPL in specific directory')}
|
|
251
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent repl ./my-app')}
|
|
329
252
|
|
|
330
|
-
${
|
|
331
|
-
${
|
|
253
|
+
${ui.format.dim('Start with file watching enabled')}
|
|
254
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent repl --watch')}
|
|
332
255
|
|
|
333
|
-
${
|
|
334
|
-
${
|
|
256
|
+
${ui.format.dim('Start in quiet mode (no startup messages)')}
|
|
257
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent repl --quiet')}
|
|
335
258
|
|
|
336
|
-
${
|
|
337
|
-
${
|
|
259
|
+
${ui.format.dim('Combine options for development workflow')}
|
|
260
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent repl . --watch')}
|
|
338
261
|
`)
|
|
339
262
|
.action(replCommand);
|
|
340
263
|
program
|
|
@@ -344,26 +267,26 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
344
267
|
.option('-p, --outputPostman <outputPostman>', 'Generate Postman collection')
|
|
345
268
|
.description('Generate API documentation (Swagger/OpenAPI)')
|
|
346
269
|
.addHelpText('after', `
|
|
347
|
-
${
|
|
270
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
348
271
|
Generates comprehensive API documentation from your Agentlang module
|
|
349
272
|
in Swagger/OpenAPI format. Supports both HTML and Postman collection
|
|
350
273
|
output formats for easy API exploration and testing.
|
|
351
274
|
|
|
352
|
-
${
|
|
353
|
-
${
|
|
354
|
-
${
|
|
275
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
276
|
+
${ui.format.dim('Generate OpenAPI spec (outputs to console)')}
|
|
277
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent doc')}
|
|
355
278
|
|
|
356
|
-
${
|
|
357
|
-
${
|
|
279
|
+
${ui.format.dim('Generate HTML documentation')}
|
|
280
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent doc --outputHtml api-docs.html')}
|
|
358
281
|
|
|
359
|
-
${
|
|
360
|
-
${
|
|
282
|
+
${ui.format.dim('Generate Postman collection')}
|
|
283
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent doc --outputPostman collection.json')}
|
|
361
284
|
|
|
362
|
-
${
|
|
363
|
-
${
|
|
285
|
+
${ui.format.dim('Generate both HTML and Postman')}
|
|
286
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent doc -h docs.html -p collection.json')}
|
|
364
287
|
|
|
365
|
-
${
|
|
366
|
-
${
|
|
288
|
+
${ui.format.dim('Generate docs for specific module')}
|
|
289
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent doc ./my-api -h api.html')}
|
|
367
290
|
`)
|
|
368
291
|
.action(generateDoc);
|
|
369
292
|
program
|
|
@@ -372,20 +295,20 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
372
295
|
.option('-d, --destination <dir>', 'Output directory for generated files')
|
|
373
296
|
.description('Parse and validate Agentlang source code')
|
|
374
297
|
.addHelpText('after', `
|
|
375
|
-
${
|
|
298
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
376
299
|
Parses and validates an Agentlang source file, checking for syntax
|
|
377
300
|
errors, lexer issues, and semantic validation problems. Useful for
|
|
378
301
|
CI/CD pipelines and pre-deployment validation.
|
|
379
302
|
|
|
380
|
-
${
|
|
381
|
-
${
|
|
382
|
-
${
|
|
303
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
304
|
+
${ui.format.dim('Validate a source file')}
|
|
305
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent parseAndValidate ./src/main.al')}
|
|
383
306
|
|
|
384
|
-
${
|
|
385
|
-
${
|
|
307
|
+
${ui.format.dim('Parse and validate with output directory')}
|
|
308
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent parseAndValidate main.al -d ./out')}
|
|
386
309
|
|
|
387
|
-
${
|
|
388
|
-
${
|
|
310
|
+
${ui.format.dim('Validate in CI/CD pipeline')}
|
|
311
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent parseAndValidate app.al && npm run deploy')}
|
|
389
312
|
`)
|
|
390
313
|
.action(parseAndValidate);
|
|
391
314
|
program
|
|
@@ -397,36 +320,36 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
397
320
|
.option('-m, --message <message>', 'User message for incremental updates')
|
|
398
321
|
.description('Generate UI from specification (requires Anthropic API key)')
|
|
399
322
|
.addHelpText('after', `
|
|
400
|
-
${
|
|
323
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
401
324
|
Generates a complete UI application from a ui-spec.json specification
|
|
402
325
|
using AI. Supports incremental updates, allowing you to evolve your UI
|
|
403
326
|
over time with natural language instructions.
|
|
404
327
|
|
|
405
|
-
${
|
|
406
|
-
Set ${
|
|
407
|
-
${
|
|
328
|
+
${ui.format.row([{ text: 'API KEY REQUIRED', color: 'yellow', bold: true }])}
|
|
329
|
+
Set ${ui.format.cyan('ANTHROPIC_API_KEY')} environment variable or use ${ui.format.cyan('--api-key')} flag
|
|
330
|
+
${ui.format.dim('Get your key at: https://console.anthropic.com')}
|
|
408
331
|
|
|
409
|
-
${
|
|
410
|
-
${
|
|
411
|
-
${
|
|
332
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
333
|
+
${ui.format.dim('Generate UI with auto-detected spec')}
|
|
334
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen')}
|
|
412
335
|
|
|
413
|
-
${
|
|
414
|
-
${
|
|
336
|
+
${ui.format.dim('Generate from specific spec file')}
|
|
337
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen ui-spec.json')}
|
|
415
338
|
|
|
416
|
-
${
|
|
417
|
-
${
|
|
339
|
+
${ui.format.dim('Generate and commit to git')}
|
|
340
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen --push')}
|
|
418
341
|
|
|
419
|
-
${
|
|
420
|
-
${
|
|
342
|
+
${ui.format.dim('Generate in specific directory')}
|
|
343
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen -d ./frontend')}
|
|
421
344
|
|
|
422
|
-
${
|
|
423
|
-
${
|
|
345
|
+
${ui.format.dim('Update existing UI with changes')}
|
|
346
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen -m "Add dark mode toggle"')}
|
|
424
347
|
|
|
425
|
-
${
|
|
426
|
-
${
|
|
348
|
+
${ui.format.dim('Incremental update with git push')}
|
|
349
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen -m "Fix login validation" -p')}
|
|
427
350
|
|
|
428
|
-
${
|
|
429
|
-
${
|
|
351
|
+
${ui.format.dim('Use custom API key')}
|
|
352
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent ui-gen --api-key sk-ant-...')}
|
|
430
353
|
`)
|
|
431
354
|
.action(generateUICommand);
|
|
432
355
|
program
|
|
@@ -438,26 +361,26 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
438
361
|
.option('-t, --token <token>', 'GitHub token for authenticated access')
|
|
439
362
|
.description('Fork an app from a local directory or git repository')
|
|
440
363
|
.addHelpText('after', `
|
|
441
|
-
${
|
|
364
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
442
365
|
Forks an Agentlang application from a source path (local directory or git URL)
|
|
443
366
|
into the current workspace. The forked app will be initialized with dependencies
|
|
444
367
|
installed and a fresh git repository.
|
|
445
368
|
|
|
446
|
-
${
|
|
447
|
-
${
|
|
448
|
-
${
|
|
369
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
370
|
+
${ui.format.dim('Fork from local directory')}
|
|
371
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent fork ./my-app MyForkedApp')}
|
|
449
372
|
|
|
450
|
-
${
|
|
451
|
-
${
|
|
373
|
+
${ui.format.dim('Fork from GitHub repository')}
|
|
374
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent fork https://github.com/user/repo.git MyApp')}
|
|
452
375
|
|
|
453
|
-
${
|
|
454
|
-
${
|
|
376
|
+
${ui.format.dim('Fork from GitHub with specific branch')}
|
|
377
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent fork https://github.com/user/repo.git MyApp --branch develop')}
|
|
455
378
|
|
|
456
|
-
${
|
|
457
|
-
${
|
|
379
|
+
${ui.format.dim('Fork private repository with authentication')}
|
|
380
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent fork https://github.com/user/repo.git MyApp -u username -t token')}
|
|
458
381
|
|
|
459
|
-
${
|
|
460
|
-
${
|
|
382
|
+
${ui.format.dim('Fork using git@ URL')}
|
|
383
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent fork git@github.com:user/repo.git MyApp')}
|
|
461
384
|
`)
|
|
462
385
|
.action(forkCommand);
|
|
463
386
|
program
|
|
@@ -469,16 +392,16 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
469
392
|
.option('-t, --token <token>', 'GitHub token for authenticated access')
|
|
470
393
|
.description('Import an app from a local directory or git repository (alias for fork)')
|
|
471
394
|
.addHelpText('after', `
|
|
472
|
-
${
|
|
395
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
473
396
|
Imports an Agentlang application from a source path. This is an alias for the
|
|
474
397
|
'fork' command and uses the same functionality.
|
|
475
398
|
|
|
476
|
-
${
|
|
477
|
-
${
|
|
478
|
-
${
|
|
399
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
400
|
+
${ui.format.dim('Import from local directory')}
|
|
401
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent import ./my-app MyImportedApp')}
|
|
479
402
|
|
|
480
|
-
${
|
|
481
|
-
${
|
|
403
|
+
${ui.format.dim('Import from GitHub repository')}
|
|
404
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent import https://github.com/user/repo.git MyApp')}
|
|
482
405
|
`)
|
|
483
406
|
.action(forkCommand);
|
|
484
407
|
program
|
|
@@ -488,7 +411,7 @@ ${chalk.bold.white('EXAMPLES')}
|
|
|
488
411
|
.option('--server-only', 'Start only the backend server without opening the UI')
|
|
489
412
|
.description('Start Agentlang Studio with local server')
|
|
490
413
|
.addHelpText('after', `
|
|
491
|
-
${
|
|
414
|
+
${ui.format.boldWhite('DESCRIPTION')}
|
|
492
415
|
Starts the Agentlang Design Studio locally for your project. This command:
|
|
493
416
|
• Starts the Agentlang server (via 'agent run')
|
|
494
417
|
• Serves the Studio UI on a local web server
|
|
@@ -497,21 +420,21 @@ ${chalk.bold.white('DESCRIPTION')}
|
|
|
497
420
|
The Studio UI allows you to visually edit Agents, Data Models, and Workflows,
|
|
498
421
|
with changes saved directly to your project files (.al files, package.json, etc.).
|
|
499
422
|
|
|
500
|
-
${
|
|
501
|
-
${
|
|
502
|
-
${
|
|
423
|
+
${ui.format.boldWhite('EXAMPLES')}
|
|
424
|
+
${ui.format.dim('Start Studio in current directory')}
|
|
425
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent studio')}
|
|
503
426
|
|
|
504
|
-
${
|
|
505
|
-
${
|
|
427
|
+
${ui.format.dim('Start Studio for specific project')}
|
|
428
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent studio ./my-project')}
|
|
506
429
|
|
|
507
|
-
${
|
|
508
|
-
${
|
|
430
|
+
${ui.format.dim('Start Studio on custom port')}
|
|
431
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent studio --port 5000')}
|
|
509
432
|
|
|
510
|
-
${
|
|
511
|
-
${
|
|
433
|
+
${ui.format.dim('Start Studio with path and custom port')}
|
|
434
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent studio ./monitoring -p 5000')}
|
|
512
435
|
|
|
513
|
-
${
|
|
514
|
-
${
|
|
436
|
+
${ui.format.dim('Start only the backend server (for development)')}
|
|
437
|
+
${ui.format.dim('$')} ${ui.format.cyan('agent studio --server-only')}
|
|
515
438
|
`)
|
|
516
439
|
.action(studioCommand);
|
|
517
440
|
program.parse(process.argv);
|
|
@@ -532,12 +455,10 @@ export const parseAndValidate = async (fileName) => {
|
|
|
532
455
|
const parseResult = document.parseResult;
|
|
533
456
|
// verify no lexer, parser, or general diagnostic errors show up
|
|
534
457
|
if (parseResult.lexerErrors.length === 0 && parseResult.parserErrors.length === 0) {
|
|
535
|
-
|
|
536
|
-
console.log(chalk.green(`Parsed and validated ${fileName} successfully!`));
|
|
458
|
+
ui.success(`Parsed and validated ${fileName} successfully!`);
|
|
537
459
|
}
|
|
538
460
|
else {
|
|
539
|
-
|
|
540
|
-
console.log(chalk.red(`Failed to parse and validate ${fileName}!`));
|
|
461
|
+
ui.error(`Failed to parse and validate ${fileName}!`);
|
|
541
462
|
}
|
|
542
463
|
};
|
|
543
464
|
export const runModule = async (fileName) => {
|
|
@@ -559,9 +480,8 @@ export const runModule = async (fileName) => {
|
|
|
559
480
|
});
|
|
560
481
|
}
|
|
561
482
|
catch (err) {
|
|
562
|
-
if (isNodeEnv
|
|
563
|
-
|
|
564
|
-
console.error(chalk.red(String(err)));
|
|
483
|
+
if (isNodeEnv) {
|
|
484
|
+
ui.error(String(err));
|
|
565
485
|
}
|
|
566
486
|
else {
|
|
567
487
|
// eslint-disable-next-line no-console
|
|
@@ -587,8 +507,7 @@ export const replCommand = async (directory, options) => {
|
|
|
587
507
|
});
|
|
588
508
|
}
|
|
589
509
|
catch (error) {
|
|
590
|
-
|
|
591
|
-
console.log(chalk.red(`Failed to start REPL: ${error instanceof Error ? error.message : String(error)}`));
|
|
510
|
+
ui.error(`Failed to start REPL: ${error instanceof Error ? error.message : String(error)}`);
|
|
592
511
|
process.exit(1);
|
|
593
512
|
}
|
|
594
513
|
};
|
|
@@ -601,20 +520,23 @@ export async function internAndRunModule(module, appSpec) {
|
|
|
601
520
|
await runPostInitTasks(appSpec);
|
|
602
521
|
return rm;
|
|
603
522
|
}
|
|
604
|
-
/* eslint-disable no-console */
|
|
605
523
|
export const generateUICommand = async (specFile, options) => {
|
|
606
524
|
try {
|
|
607
|
-
|
|
525
|
+
ui.blank();
|
|
526
|
+
ui.banner('UI Generator');
|
|
527
|
+
ui.blank();
|
|
608
528
|
// Get API key from options or environment
|
|
609
529
|
const apiKey = (options === null || options === void 0 ? void 0 : options.apiKey) || process.env.ANTHROPIC_API_KEY;
|
|
610
530
|
if (!apiKey) {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
531
|
+
ui.error('Anthropic API key is required.');
|
|
532
|
+
ui.warn('Set ANTHROPIC_API_KEY environment variable or use --api-key flag.');
|
|
533
|
+
ui.blank();
|
|
534
|
+
ui.gray(' Example:');
|
|
535
|
+
ui.gray(' $ export ANTHROPIC_API_KEY=sk-ant-...');
|
|
536
|
+
ui.gray(' $ agent ui-gen');
|
|
537
|
+
ui.blank();
|
|
538
|
+
ui.gray(' Or:');
|
|
539
|
+
ui.gray(' $ agent ui-gen --api-key sk-ant-...');
|
|
618
540
|
process.exit(1);
|
|
619
541
|
}
|
|
620
542
|
// Set target directory
|
|
@@ -623,52 +545,51 @@ export const generateUICommand = async (specFile, options) => {
|
|
|
623
545
|
// Auto-detect spec file if not provided
|
|
624
546
|
let specFilePath;
|
|
625
547
|
if (!specFile) {
|
|
626
|
-
|
|
548
|
+
ui.dim('Searching for UI spec file...');
|
|
627
549
|
specFilePath = await findSpecFile(absoluteTargetDir);
|
|
628
550
|
}
|
|
629
551
|
else {
|
|
630
552
|
specFilePath = path.resolve(process.cwd(), specFile);
|
|
631
553
|
}
|
|
632
554
|
// Load the UI spec
|
|
633
|
-
console.log(chalk.cyan(`📄 Loading UI spec from: ${specFilePath}`));
|
|
634
555
|
const uiSpec = await loadUISpec(specFilePath);
|
|
635
|
-
|
|
636
|
-
|
|
556
|
+
ui.label('Spec', specFilePath, 'cyan');
|
|
557
|
+
ui.label('Target', absoluteTargetDir);
|
|
558
|
+
ui.label('Output', path.join(absoluteTargetDir, 'ui'));
|
|
559
|
+
ui.blank();
|
|
637
560
|
// Generate or update the UI
|
|
638
561
|
await generateUI(uiSpec, absoluteTargetDir, apiKey, (options === null || options === void 0 ? void 0 : options.push) || false, options === null || options === void 0 ? void 0 : options.message);
|
|
639
|
-
|
|
562
|
+
ui.blank();
|
|
563
|
+
ui.divider(50);
|
|
564
|
+
ui.success('UI generation completed!');
|
|
565
|
+
ui.divider(50);
|
|
566
|
+
ui.blank();
|
|
640
567
|
}
|
|
641
568
|
catch (error) {
|
|
642
|
-
|
|
569
|
+
ui.error(error instanceof Error ? error.message : String(error));
|
|
643
570
|
process.exit(1);
|
|
644
571
|
}
|
|
645
572
|
};
|
|
646
|
-
/* eslint-enable no-console */
|
|
647
|
-
/* eslint-disable no-console */
|
|
648
573
|
export const studioCommand = async (projectPath, options) => {
|
|
649
574
|
try {
|
|
650
575
|
const port = parseInt((options === null || options === void 0 ? void 0 : options.port) || '4000', 10);
|
|
651
576
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
652
|
-
|
|
577
|
+
ui.error('Invalid port number. Port must be between 1 and 65535.');
|
|
653
578
|
process.exit(1);
|
|
654
579
|
}
|
|
655
580
|
await startStudio(projectPath || '.', port, options === null || options === void 0 ? void 0 : options.serverOnly);
|
|
656
581
|
}
|
|
657
582
|
catch (error) {
|
|
658
|
-
|
|
583
|
+
ui.error(`Failed to start Studio: ${error instanceof Error ? error.message : String(error)}`);
|
|
659
584
|
process.exit(1);
|
|
660
585
|
}
|
|
661
586
|
};
|
|
662
|
-
/* eslint-enable no-console */
|
|
663
|
-
/* eslint-disable no-console */
|
|
664
587
|
export const forkCommand = async (source, name, options) => {
|
|
665
588
|
try {
|
|
666
|
-
console.log(chalk.blue('🚀 Forking Agentlang application...\n'));
|
|
667
589
|
// Determine destination name
|
|
668
590
|
let appName = name;
|
|
669
591
|
if (!appName) {
|
|
670
592
|
if (source.startsWith('http') || source.startsWith('git@')) {
|
|
671
|
-
// Try to infer from URL
|
|
672
593
|
const parts = source.split('/');
|
|
673
594
|
const lastPart = parts[parts.length - 1].replace('.git', '');
|
|
674
595
|
appName = lastPart;
|
|
@@ -690,24 +611,41 @@ export const forkCommand = async (source, name, options) => {
|
|
|
690
611
|
token: options.token,
|
|
691
612
|
};
|
|
692
613
|
}
|
|
693
|
-
|
|
694
|
-
|
|
614
|
+
ui.blank();
|
|
615
|
+
ui.banner('Fork App');
|
|
616
|
+
ui.blank();
|
|
617
|
+
ui.label('Source', source, 'cyan');
|
|
618
|
+
ui.label('Destination', destPath);
|
|
695
619
|
if (options === null || options === void 0 ? void 0 : options.branch) {
|
|
696
|
-
|
|
620
|
+
ui.label('Branch', options.branch, 'cyan');
|
|
697
621
|
}
|
|
698
622
|
if (forkOptions.credentials) {
|
|
699
|
-
|
|
623
|
+
ui.label('Auth', forkOptions.credentials.username, 'cyan');
|
|
700
624
|
}
|
|
625
|
+
ui.blank();
|
|
701
626
|
// Perform the fork
|
|
702
627
|
const result = await forkApp(source, destPath, forkOptions);
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
628
|
+
ui.divider(50);
|
|
629
|
+
ui.success(`Forked "${result.name}" successfully!`);
|
|
630
|
+
ui.blank();
|
|
631
|
+
ui.dim('Next steps:');
|
|
632
|
+
ui.row([
|
|
633
|
+
{ text: ' 1. Change directory: ', dimColor: true },
|
|
634
|
+
{ text: `cd ${result.name}`, color: 'cyan' },
|
|
635
|
+
]);
|
|
636
|
+
ui.row([
|
|
637
|
+
{ text: ' 2. Run your app: ', dimColor: true },
|
|
638
|
+
{ text: 'agent run', color: 'cyan' },
|
|
639
|
+
]);
|
|
640
|
+
ui.row([
|
|
641
|
+
{ text: ' 3. Or start Studio: ', dimColor: true },
|
|
642
|
+
{ text: 'agent studio', color: 'cyan' },
|
|
643
|
+
]);
|
|
644
|
+
ui.divider(50);
|
|
645
|
+
ui.blank();
|
|
708
646
|
}
|
|
709
647
|
catch (error) {
|
|
710
|
-
|
|
648
|
+
ui.error(error instanceof Error ? error.message : String(error));
|
|
711
649
|
process.exit(1);
|
|
712
650
|
}
|
|
713
651
|
};
|