@agentlang/cli 0.6.6

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/repl.js ADDED
@@ -0,0 +1,785 @@
1
+ import * as readline from 'node:readline';
2
+ import * as path from 'node:path';
3
+ import * as chokidar from 'chokidar';
4
+ import chalk from 'chalk';
5
+ import { load, loadRawConfig, parseAndIntern } from 'agentlang/out/runtime/loader.js';
6
+ import { addModule, getActiveModuleName, fetchModule, getUserModuleNames, getEntity, addEntity, removeEntity, getRecord, addRecord, removeRecord, getRelationship, addRelationship, removeRelationship, getWorkflow, addWorkflow, removeWorkflow, getEvent, addEvent, removeEvent, removeModule, } from 'agentlang/out/runtime/module.js';
7
+ import { addFromDef, addRelationshipFromDef, addWorkflowFromDef } from 'agentlang/out/runtime/loader.js';
8
+ import { parseModule } from 'agentlang/out/language/parser.js';
9
+ import { isEntityDefinition, isEventDefinition, isRecordDefinition, isRelationshipDefinition, isWorkflowDefinition, } from 'agentlang/out/language/generated/ast.js';
10
+ import { setAppConfig } from 'agentlang/out/runtime/state.js';
11
+ import { runPreInitTasks, runPostInitTasks } from './main.js';
12
+ import { lookupAllInstances, parseAndEvaluateStatement } from 'agentlang/out/runtime/interpreter.js';
13
+ // Global REPL state
14
+ let replState = null;
15
+ // Core AgentLang processing function
16
+ async function processAgentlang(code) {
17
+ let currentModule = getActiveModuleName();
18
+ if (!currentModule && (replState === null || replState === void 0 ? void 0 : replState.appSpec) && 'name' in replState.appSpec) {
19
+ currentModule = replState.appSpec.name;
20
+ }
21
+ if (!currentModule) {
22
+ throw new Error('No active module found. Please ensure the application is loaded.');
23
+ }
24
+ // For individual definitions, use a different approach to avoid module replacement
25
+ const trimmedCode = code.trim();
26
+ // Check if it's a simple entity, record, event, or relationship definition
27
+ if (trimmedCode.startsWith('entity ') ||
28
+ trimmedCode.startsWith('record ') ||
29
+ trimmedCode.startsWith('event ') ||
30
+ trimmedCode.startsWith('relationship ') ||
31
+ trimmedCode.startsWith('workflow ')) {
32
+ try {
33
+ // Parse the definition in a temporary module context to get the AST
34
+ const tempModuleName = `__temp_${Date.now()}`;
35
+ const wrappedCode = `module ${tempModuleName}\n\n${code}`;
36
+ const parsedModule = await parseModule(wrappedCode);
37
+ // Extract the definition from the parsed module
38
+ if (parsedModule.defs && parsedModule.defs.length > 0) {
39
+ const def = parsedModule.defs[0];
40
+ // Use the appropriate specific function based on the definition type
41
+ if (isEntityDefinition(def) || isEventDefinition(def) || isRecordDefinition(def)) {
42
+ await addFromDef(def, currentModule);
43
+ }
44
+ else if (isRelationshipDefinition(def)) {
45
+ addRelationshipFromDef(def, currentModule);
46
+ }
47
+ else if (isWorkflowDefinition(def)) {
48
+ addWorkflowFromDef(def, currentModule);
49
+ }
50
+ else {
51
+ // Fall back to the general addFromDef for other types
52
+ await addFromDef(def, currentModule);
53
+ }
54
+ return '✓ AgentLang code processed successfully';
55
+ }
56
+ else {
57
+ throw new Error('No definitions found in parsed code');
58
+ }
59
+ }
60
+ catch (error) {
61
+ // If the custom approach fails, fall back to the original method
62
+ // eslint-disable-next-line no-console
63
+ console.warn('Custom parsing failed, falling back to original method:', error);
64
+ await parseAndIntern(code, currentModule);
65
+ return '✓ AgentLang code processed successfully';
66
+ }
67
+ }
68
+ else {
69
+ // For complex code or module-level statements, use the original approach
70
+ await parseAndIntern(code, currentModule);
71
+ return '✓ AgentLang code processed successfully';
72
+ }
73
+ }
74
+ // REPL Helper Functions - Multiple syntax styles like original Deno REPL
75
+ function createReplHelpers() {
76
+ // Template literal and function syntax for AgentLang code
77
+ const al = function (strings, ...values) {
78
+ if (Array.isArray(strings) && 'raw' in strings) {
79
+ // Template literal: al`entity User { name String }`
80
+ const code = strings.reduce((acc, str, i) => {
81
+ const value = values[i];
82
+ let valueStr = '';
83
+ if (value !== undefined) {
84
+ if (typeof value === 'object' && value !== null) {
85
+ valueStr = JSON.stringify(value);
86
+ }
87
+ else if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
88
+ valueStr = String(value);
89
+ }
90
+ else {
91
+ valueStr = '[object]';
92
+ }
93
+ }
94
+ return acc + str + valueStr;
95
+ }, '');
96
+ return processAgentlang(code);
97
+ }
98
+ else if (typeof strings === 'string') {
99
+ // Function call: al("entity User { name String }")
100
+ return processAgentlang(strings);
101
+ }
102
+ throw new Error("Invalid usage of al(). Use al`code` or al('code')");
103
+ };
104
+ // Enhanced entity function - multiple syntax styles
105
+ const e = function (name, definition) {
106
+ if (typeof name === 'string' && typeof definition === 'object') {
107
+ // Object style: e("User", { name: "String", age: "Int" })
108
+ const fields = Object.entries(definition)
109
+ .map(([key, type]) => ` ${key} ${type}`)
110
+ .join('\n');
111
+ const code = `entity ${name} {\n${fields}\n}`;
112
+ return processAgentlang(code);
113
+ }
114
+ else if (typeof name === 'string' && typeof definition === 'string') {
115
+ // String style: e("User", "{ id String @id, name String }")
116
+ const cleanDef = definition.trim();
117
+ const fieldsContent = cleanDef.startsWith('{') && cleanDef.endsWith('}') ? cleanDef.slice(1, -1).trim() : cleanDef;
118
+ const code = `entity ${name} { ${fieldsContent} }`;
119
+ return processAgentlang(code);
120
+ }
121
+ else if (typeof name === 'string' && !definition) {
122
+ // Simple style: e("User")
123
+ const code = `entity ${name} {}`;
124
+ return processAgentlang(code);
125
+ }
126
+ throw new Error("Invalid usage of e(). Use e('Name', {fields}) or e('Name', 'fields') or e('Name')");
127
+ };
128
+ // Record function
129
+ const r = function (name, definition) {
130
+ if (typeof name === 'string' && typeof definition === 'object') {
131
+ const fields = Object.entries(definition)
132
+ .map(([key, type]) => ` ${key} ${type}`)
133
+ .join('\n');
134
+ const code = `record ${name} {\n${fields}\n}`;
135
+ return processAgentlang(code);
136
+ }
137
+ else if (typeof name === 'string' && typeof definition === 'string') {
138
+ const cleanDef = definition.trim();
139
+ const fieldsContent = cleanDef.startsWith('{') && cleanDef.endsWith('}') ? cleanDef.slice(1, -1).trim() : cleanDef;
140
+ const code = `record ${name} { ${fieldsContent} }`;
141
+ return processAgentlang(code);
142
+ }
143
+ else if (typeof name === 'string' && !definition) {
144
+ const code = `record ${name} {}`;
145
+ return processAgentlang(code);
146
+ }
147
+ throw new Error("Invalid usage of r(). Use r('Name', {fields}) or r('Name', 'fields') or r('Name')");
148
+ };
149
+ // Event function
150
+ const ev = function (name, definition) {
151
+ if (typeof name === 'string' && typeof definition === 'object') {
152
+ const fields = Object.entries(definition)
153
+ .map(([key, type]) => ` ${key} ${type}`)
154
+ .join('\n');
155
+ const code = `event ${name} {\n${fields}\n}`;
156
+ return processAgentlang(code);
157
+ }
158
+ else if (typeof name === 'string' && typeof definition === 'string') {
159
+ const cleanDef = definition.trim();
160
+ const fieldsContent = cleanDef.startsWith('{') && cleanDef.endsWith('}') ? cleanDef.slice(1, -1).trim() : cleanDef;
161
+ const code = `event ${name} { ${fieldsContent} }`;
162
+ return processAgentlang(code);
163
+ }
164
+ else if (typeof name === 'string' && !definition) {
165
+ const code = `event ${name} {}`;
166
+ return processAgentlang(code);
167
+ }
168
+ throw new Error("Invalid usage of ev(). Use ev('Name', {fields}) or ev('Name', 'fields') or ev('Name')");
169
+ };
170
+ // Relationship function
171
+ const rel = function (name, type, nodes) {
172
+ if (nodes.length !== 2) {
173
+ throw new Error('Relationship requires exactly 2 nodes');
174
+ }
175
+ const code = `relationship ${name} { ${type} [${nodes.join(', ')}] }`;
176
+ return processAgentlang(code);
177
+ };
178
+ // Workflow function
179
+ const w = function (name, statements) {
180
+ const stmts = statements ? statements.join('\n ') : '';
181
+ const code = `workflow ${name} {\n ${stmts}\n}`;
182
+ return processAgentlang(code);
183
+ };
184
+ // Instance creation helper
185
+ const inst = async function (entityName, attributes) {
186
+ const currentModule = getActiveModuleName();
187
+ if (!currentModule) {
188
+ throw new Error('No active module found');
189
+ }
190
+ // Helper to format values for AgentLang syntax
191
+ const formatValue = (value) => {
192
+ var _a;
193
+ if (typeof value === 'string') {
194
+ return `"${value}"`;
195
+ }
196
+ else if (typeof value === 'number' || typeof value === 'boolean') {
197
+ return String(value);
198
+ }
199
+ else if (Array.isArray(value)) {
200
+ return `[${value.map(formatValue).join(', ')}]`;
201
+ }
202
+ else if (value === null || value === undefined) {
203
+ return 'nil';
204
+ }
205
+ else if (typeof value === 'object') {
206
+ const entries = Object.entries(value)
207
+ .map(([k, v]) => `${k} ${formatValue(v)}`)
208
+ .join(', ');
209
+ return `{${entries}}`;
210
+ }
211
+ // For unsupported types, use JSON.stringify as fallback
212
+ return (_a = JSON.stringify(value)) !== null && _a !== void 0 ? _a : 'nil';
213
+ };
214
+ // Build the statement string
215
+ const fields = Object.entries(attributes)
216
+ .map(([key, value]) => `${key} ${formatValue(value)}`)
217
+ .join(', ');
218
+ const statement = `{${currentModule}/${entityName} {${fields}}}`;
219
+ // Parse and evaluate the statement
220
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
221
+ const result = await parseAndEvaluateStatement(statement);
222
+ return result;
223
+ };
224
+ // Module management object
225
+ const m = {
226
+ list: () => getUserModuleNames(),
227
+ get: (name) => fetchModule(name),
228
+ active: () => getActiveModuleName(),
229
+ add: (name) => addModule(name),
230
+ remove: (name) => removeModule(name),
231
+ };
232
+ // Inspection utilities
233
+ const inspect = {
234
+ modules: () => {
235
+ const modules = getUserModuleNames();
236
+ // eslint-disable-next-line no-console
237
+ console.log(chalk.blue('📦 Available Modules:'));
238
+ // eslint-disable-next-line no-console
239
+ modules.forEach(mod => console.log(` • ${mod}`));
240
+ return modules;
241
+ },
242
+ entities: (moduleName) => {
243
+ const mod = moduleName ? fetchModule(moduleName) : fetchModule(getActiveModuleName());
244
+ const entities = mod.getEntityNames();
245
+ // eslint-disable-next-line no-console
246
+ console.log(chalk.green(`🏗️ Entities in ${mod.name}:`));
247
+ // eslint-disable-next-line no-console
248
+ entities.forEach(ent => console.log(` • ${ent}`));
249
+ return entities;
250
+ },
251
+ events: (moduleName) => {
252
+ const mod = moduleName ? fetchModule(moduleName) : fetchModule(getActiveModuleName());
253
+ const events = mod.getEventNames();
254
+ // eslint-disable-next-line no-console
255
+ console.log(chalk.yellow(`⚡ Events in ${mod.name}:`));
256
+ // eslint-disable-next-line no-console
257
+ events.forEach(evt => console.log(` • ${evt}`));
258
+ return events;
259
+ },
260
+ relationships: (moduleName) => {
261
+ const mod = moduleName ? fetchModule(moduleName) : fetchModule(getActiveModuleName());
262
+ const rels = mod.getRelationshipNames();
263
+ // eslint-disable-next-line no-console
264
+ console.log(chalk.magenta(`🔗 Relationships in ${mod.name}:`));
265
+ // eslint-disable-next-line no-console
266
+ rels.forEach(rel => console.log(` • ${rel}`));
267
+ return rels;
268
+ },
269
+ instances: async (entityName) => {
270
+ if (!entityName) {
271
+ throw new Error('entityName is required');
272
+ }
273
+ const instances = await lookupAllInstances(entityName);
274
+ // eslint-disable-next-line no-console
275
+ console.log(chalk.cyan(`🏭 Instances for ${entityName}:`));
276
+ return instances;
277
+ },
278
+ };
279
+ // Utility functions
280
+ const utils = {
281
+ help: () => {
282
+ /* eslint-disable no-console */
283
+ console.log(chalk.blue.bold('\n🚀 AgentLang REPL - Comprehensive Guide\n'));
284
+ console.log(chalk.green.bold('📋 Basic Commands:'));
285
+ console.log(' help, ? // Show this help');
286
+ console.log(' exit, quit // Exit REPL');
287
+ console.log(' clear // Clear screen');
288
+ console.log(' restart // Restart REPL');
289
+ console.log(chalk.cyan.bold('\n🏗️ Entity Creation:'));
290
+ console.log(' e("User") // Empty entity');
291
+ console.log(' e("User", {name: "String"}) // Object syntax');
292
+ console.log(' e("User", "name String, age Int") // String syntax');
293
+ console.log(' entity("User", {id: "String @id"}) // Alias for e()');
294
+ console.log(chalk.magenta.bold('\n📄 Record Creation:'));
295
+ console.log(' r("Config") // Empty record');
296
+ console.log(' r("Config", {key: "String"}) // Object syntax');
297
+ console.log(' r("Config", "key String, val Any") // String syntax');
298
+ console.log(' record("Config", {settings: "Map"}) // Alias for r()');
299
+ console.log(chalk.yellow.bold('\n⚡ Event Creation:'));
300
+ console.log(' ev("UserCreated") // Empty event');
301
+ console.log(' ev("UserCreated", {id: "String"}) // Object syntax');
302
+ console.log(' ev("UserCreated", "id String") // String syntax');
303
+ console.log(' event("UserCreated", {data: "Map"}) // Alias for ev()');
304
+ console.log(chalk.red.bold('\n🔗 Relationship Creation:'));
305
+ console.log(' rel("UserPosts", "contains", ["User", "Post"])');
306
+ console.log(' rel("Friendship", "between", ["User", "User"])');
307
+ console.log(' relationship("Owns", "contains", ["User", "Asset"])');
308
+ console.log(chalk.blue.bold('\n🔄 Workflow Creation:'));
309
+ console.log(' w("ProcessUser") // Empty workflow');
310
+ console.log(' w("ProcessUser", ["step1", "step2"]) // With steps');
311
+ console.log(' workflow("HandleOrder", ["validate", "process"])');
312
+ console.log(chalk.green.bold('\n🏭 Instance Creation:'));
313
+ console.log(' inst("User", {name: "John", age: 30})');
314
+ console.log(' instance("Post", {title: "Hello", content: "World"})');
315
+ console.log(chalk.cyan.bold('\n📝 Template Literal Usage:'));
316
+ console.log(' al`entity User { name String }` // AgentLang code');
317
+ console.log(' al`record Config { key String }` // Multi-line supported');
318
+ console.log(' al("entity User { name String }") // Function syntax');
319
+ console.log(' ag`event Created { id String }` // Alias for al');
320
+ console.log(chalk.magenta.bold('\n📦 Module Management (m.*):'));
321
+ console.log(' m.active() // Get active module name');
322
+ console.log(' m.list() // List all user modules');
323
+ console.log(' m.get("MyApp") // Get specific module');
324
+ console.log(' m.add("NewMod") // Add new module');
325
+ console.log(' m.remove("Mod") // Remove module');
326
+ console.log(' modules.active() // Alias for m.active()');
327
+ console.log(chalk.yellow.bold('\n🔍 Inspection Commands (inspect.*):'));
328
+ console.log(' inspect.modules() // List all modules');
329
+ console.log(' inspect.entities() // List entities in active module');
330
+ console.log(' inspect.entities("MyApp") // List entities in specific module');
331
+ console.log(' inspect.events() // List events in active module');
332
+ console.log(' inspect.events("MyApp") // List events in specific module');
333
+ console.log(' inspect.relationships() // List relationships in active module');
334
+ console.log(' inspect.relationships("MyApp") // List relationships in specific module');
335
+ console.log(' inspect.instances("MyApp/EntityName") // List instances created for an entity');
336
+ console.log(chalk.red.bold('\n🛠️ Direct Runtime Functions (requires full qualified names in string: "<ModuleName>/<Name>"):'));
337
+ console.log(chalk.white(' Entity Management:'));
338
+ console.log(' addEntity(name, definition) // Add entity to runtime');
339
+ console.log(' removeEntity(name) // Remove entity from runtime');
340
+ console.log(' getEntity(name) // Get entity definition');
341
+ console.log(chalk.white(' Record Management:'));
342
+ console.log(' addRecord(name, definition) // Add record to runtime');
343
+ console.log(' removeRecord(name) // Remove record from runtime');
344
+ console.log(' getRecord(name) // Get record definition');
345
+ console.log(chalk.white(' Event Management:'));
346
+ console.log(' addEvent(name, definition) // Add event to runtime');
347
+ console.log(' removeEvent(name) // Remove event from runtime');
348
+ console.log(' getEvent(name) // Get event definition');
349
+ console.log(chalk.white(' Relationship Management:'));
350
+ console.log(' addRelationship(name, def) // Add relationship to runtime');
351
+ console.log(' removeRelationship(name) // Remove relationship from runtime');
352
+ console.log(' getRelationship(name) // Get relationship definition');
353
+ console.log(chalk.white(' Workflow Management:'));
354
+ console.log(' addWorkflow(name, definition) // Add workflow to runtime');
355
+ console.log(' removeWorkflow(name) // Remove workflow from runtime');
356
+ console.log(' getWorkflow(name) // Get workflow definition');
357
+ console.log(chalk.white(' Core Processing:'));
358
+ console.log(' processAgentlang(code) // Process raw AgentLang code');
359
+ console.log(' parseAndEvaluateStatement(stmt) // Parse and evaluate AgentLang statement');
360
+ console.log(' // Example: parseAndEvaluateStatement("{MyApp/User {id 1, name \\"Alice\\"}}");');
361
+ console.log(chalk.gray.bold('\n🛠️ Utility Commands (utils.*):'));
362
+ console.log(' utils.help() // Show this help');
363
+ console.log(' utils.clear() // Clear screen');
364
+ console.log(' utils.restart() // Restart REPL');
365
+ console.log(' utils.exit() // Exit REPL');
366
+ console.log(chalk.gray.bold('\n💡 Tips:'));
367
+ console.log(' • Use tab completion for commands');
368
+ console.log(' • Template literals support multi-line code');
369
+ console.log(' • All functions return promises - use await if needed');
370
+ console.log(' • File watching auto-restarts on changes (if enabled)');
371
+ console.log(' • Use inspect.* commands to explore your application');
372
+ console.log(chalk.blue('\n📚 Examples:'));
373
+ console.log(' al`entity User { id String @id, name String }`');
374
+ console.log(' inst("User", {id: "123", name: "Alice"})');
375
+ console.log(' inspect.entities()');
376
+ console.log(' inspect.instances(MyApp/EntityName)');
377
+ console.log(' m.active()');
378
+ /* eslint-enable no-console */
379
+ return '';
380
+ },
381
+ clear: () => {
382
+ // eslint-disable-next-line no-console
383
+ console.log('\x1b[2J\x1b[0f');
384
+ return '';
385
+ },
386
+ restart: async () => {
387
+ // eslint-disable-next-line no-console
388
+ console.log(chalk.yellow('🔄 Restarting REPL...'));
389
+ await restartRepl();
390
+ return '';
391
+ },
392
+ exit: () => {
393
+ // eslint-disable-next-line no-console
394
+ console.log(chalk.yellow('\n👋 Goodbye!'));
395
+ cleanup();
396
+ process.exit(0);
397
+ },
398
+ };
399
+ return {
400
+ al,
401
+ ag: al, // Alias
402
+ e,
403
+ entity: e, // Alias
404
+ r,
405
+ record: r, // Alias
406
+ ev,
407
+ event: ev, // Alias
408
+ rel,
409
+ relationship: rel, // Alias
410
+ w,
411
+ workflow: w, // Alias
412
+ inst,
413
+ instance: inst, // Alias
414
+ m,
415
+ modules: m, // Alias
416
+ inspect,
417
+ utils,
418
+ // Direct access to runtime functions
419
+ addEntity,
420
+ removeEntity,
421
+ getEntity,
422
+ addRecord,
423
+ removeRecord,
424
+ getRecord,
425
+ addEvent,
426
+ removeEvent,
427
+ getEvent,
428
+ addRelationship,
429
+ removeRelationship,
430
+ getRelationship,
431
+ addWorkflow,
432
+ removeWorkflow,
433
+ getWorkflow,
434
+ processAgentlang,
435
+ parseAndEvaluateStatement,
436
+ };
437
+ }
438
+ // Setup file watcher for app directory
439
+ function setupFileWatcher(appDir, options) {
440
+ const debounceMs = options.debounceMs || 1000;
441
+ let restartTimeout;
442
+ let isWatcherReady = false;
443
+ const debouncedRestart = () => {
444
+ // Only restart if watcher is ready and not in initial startup phase
445
+ if (!isWatcherReady || !replState || replState.isRestarting || replState.isInitializing)
446
+ return;
447
+ if (restartTimeout)
448
+ clearTimeout(restartTimeout);
449
+ restartTimeout = setTimeout(() => {
450
+ if (!(replState === null || replState === void 0 ? void 0 : replState.isRestarting) && !(replState === null || replState === void 0 ? void 0 : replState.isInitializing)) {
451
+ void restartRepl();
452
+ }
453
+ }, debounceMs);
454
+ };
455
+ const watcher = chokidar.watch([path.join(appDir, '**/*.al'), path.join(appDir, '**/*.json'), path.join(appDir, 'app.config.json')], {
456
+ ignored: ['**/node_modules/**', '**/.git/**', '**/out/**', '**/dist/**'],
457
+ persistent: true,
458
+ ignoreInitial: true, // Ignore initial add events for existing files
459
+ });
460
+ watcher
461
+ .on('ready', () => {
462
+ // Mark watcher as ready after initial scan is complete
463
+ isWatcherReady = true;
464
+ })
465
+ .on('change', filePath => {
466
+ if (!options.quiet && isWatcherReady) {
467
+ // eslint-disable-next-line no-console
468
+ console.log(chalk.blue(`\n📁 File changed: ${path.relative(appDir, filePath)}`));
469
+ }
470
+ debouncedRestart();
471
+ })
472
+ .on('add', filePath => {
473
+ if (!options.quiet && isWatcherReady) {
474
+ // eslint-disable-next-line no-console
475
+ console.log(chalk.green(`\n📁 File added: ${path.relative(appDir, filePath)}`));
476
+ }
477
+ debouncedRestart();
478
+ })
479
+ .on('unlink', filePath => {
480
+ if (!options.quiet && isWatcherReady) {
481
+ // eslint-disable-next-line no-console
482
+ console.log(chalk.red(`\n📁 File removed: ${path.relative(appDir, filePath)}`));
483
+ }
484
+ debouncedRestart();
485
+ })
486
+ .on('error', (error) => {
487
+ // eslint-disable-next-line no-console
488
+ console.error(chalk.red(`Watcher error: ${String(error)}`));
489
+ });
490
+ return watcher;
491
+ }
492
+ // Restart REPL functionality
493
+ async function restartRepl() {
494
+ if (!replState || replState.isRestarting)
495
+ return;
496
+ replState.isRestarting = true;
497
+ try {
498
+ // eslint-disable-next-line no-console
499
+ console.log(chalk.yellow('\n🔄 Restarting AgentLang REPL...'));
500
+ // Reload the application
501
+ if (replState.appDir) {
502
+ await loadApplication(replState.appDir);
503
+ }
504
+ // eslint-disable-next-line no-console
505
+ console.log(chalk.green('✅ REPL restarted successfully'));
506
+ // eslint-disable-next-line no-console
507
+ console.log(chalk.blue('💬 Ready for input\n'));
508
+ }
509
+ catch (error) {
510
+ // eslint-disable-next-line no-console
511
+ console.error(chalk.red(`❌ Failed to restart: ${String(error)}`));
512
+ }
513
+ finally {
514
+ replState.isRestarting = false;
515
+ }
516
+ }
517
+ // Load AgentLang application
518
+ async function loadApplication(appDir) {
519
+ if (!replState)
520
+ return;
521
+ // Load configuration if available
522
+ try {
523
+ const configPath = path.join(appDir, 'app.config.json');
524
+ const rawConfig = (await loadRawConfig(configPath));
525
+ replState.config = setAppConfig(rawConfig);
526
+ // eslint-disable-next-line no-console
527
+ console.log(chalk.blue(`📋 Loaded config from ${configPath}`));
528
+ }
529
+ catch (_a) {
530
+ // Config is optional
531
+ if (!replState.options.quiet) {
532
+ // eslint-disable-next-line no-console
533
+ console.log(chalk.yellow('⚠️ No app.config.json found, using defaults'));
534
+ }
535
+ }
536
+ // Load the application
537
+ // eslint-disable-next-line no-console
538
+ console.log(chalk.blue(`📂 Loading application from: ${appDir}`));
539
+ await load(appDir, undefined, async (appSpec) => {
540
+ if (replState) {
541
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
542
+ replState.appSpec = appSpec;
543
+ if (appSpec && 'name' in appSpec) {
544
+ // eslint-disable-next-line no-console
545
+ console.log(chalk.green(`✅ Loaded application: ${appSpec.name}`));
546
+ }
547
+ }
548
+ await runPostInitTasks(appSpec, replState === null || replState === void 0 ? void 0 : replState.config);
549
+ });
550
+ }
551
+ // Setup signal handlers
552
+ function setupSignalHandlers() {
553
+ const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
554
+ signals.forEach(signal => {
555
+ process.on(signal, () => {
556
+ // eslint-disable-next-line no-console
557
+ console.log(chalk.yellow(`\n\n🛑 Received ${signal}, shutting down gracefully...`));
558
+ cleanup();
559
+ process.exit(0);
560
+ });
561
+ });
562
+ }
563
+ // Cleanup function
564
+ function cleanup() {
565
+ if (replState) {
566
+ // Close readline interface
567
+ replState.rl.close();
568
+ // Stop file watcher
569
+ if (replState.watcher) {
570
+ void replState.watcher.close();
571
+ }
572
+ }
573
+ }
574
+ // Main REPL function
575
+ export async function startRepl(appDir = '.', options = {}) {
576
+ // eslint-disable-next-line no-console
577
+ console.log(chalk.blue.bold('🚀 Starting AgentLang REPL...\n'));
578
+ // Setup signal handlers
579
+ setupSignalHandlers();
580
+ // Resolve app directory
581
+ const resolvedAppDir = path.resolve(process.cwd(), appDir);
582
+ // Initialize REPL state
583
+ replState = {
584
+ appDir: resolvedAppDir,
585
+ options,
586
+ rl: readline.createInterface({
587
+ input: process.stdin,
588
+ output: process.stdout,
589
+ prompt: chalk.cyan('agentlang> '),
590
+ completer: (line) => {
591
+ const completions = [
592
+ 'help',
593
+ '?',
594
+ 'exit',
595
+ 'quit',
596
+ 'clear',
597
+ 'restart',
598
+ 'al`',
599
+ 'al(',
600
+ 'e(',
601
+ 'r(',
602
+ 'ev(',
603
+ 'rel(',
604
+ 'w(',
605
+ 'inst(',
606
+ 'm.list()',
607
+ 'm.active()',
608
+ 'm.get(',
609
+ 'm.add(',
610
+ 'm.remove(',
611
+ 'inspect.modules()',
612
+ 'inspect.entities()',
613
+ 'inspect.events()',
614
+ 'inspect.relationships(',
615
+ 'inspect.instances(',
616
+ 'utils.help()',
617
+ 'utils.clear()',
618
+ 'utils.restart()',
619
+ 'utils.exit()',
620
+ 'addEntity(',
621
+ 'removeEntity(',
622
+ 'getEntity(',
623
+ 'addRecord(',
624
+ 'removeRecord(',
625
+ 'getRecord(',
626
+ 'updateRecord(',
627
+ 'queryRecords(',
628
+ 'deleteRecord(',
629
+ 'listRecords(',
630
+ 'countRecords(',
631
+ 'existsRecord(',
632
+ 'findRecord(',
633
+ 'findRecords(',
634
+ 'createRecord(',
635
+ 'upsertRecord(',
636
+ 'bulkInsert(',
637
+ 'bulkUpdate(',
638
+ 'bulkDelete(',
639
+ 'transaction(',
640
+ 'parseAndEvaluateStatement(',
641
+ 'processAgentlang(',
642
+ ];
643
+ const hits = completions.filter(c => c.startsWith(line));
644
+ return [hits.length ? hits : completions, line];
645
+ },
646
+ }),
647
+ isRestarting: false,
648
+ isInitializing: true,
649
+ };
650
+ try {
651
+ // Initialize AgentLang runtime
652
+ const success = await runPreInitTasks();
653
+ if (!success) {
654
+ throw new Error('Failed to initialize runtime');
655
+ }
656
+ // Load the application if directory is specified
657
+ if (appDir && appDir.trim() && appDir !== '.') {
658
+ await loadApplication(resolvedAppDir);
659
+ }
660
+ else {
661
+ // Try to load from current directory
662
+ try {
663
+ await loadApplication(process.cwd());
664
+ }
665
+ catch (_a) {
666
+ // eslint-disable-next-line no-console
667
+ console.log(chalk.blue('📂 Starting REPL without loading an application'));
668
+ await runPostInitTasks();
669
+ }
670
+ }
671
+ // eslint-disable-next-line no-console
672
+ console.log(chalk.green('✅ AgentLang runtime initialized'));
673
+ // Setup file watcher AFTER initial load to prevent immediate restart
674
+ if (options.watch && appDir !== '') {
675
+ // Give the initial load time to complete before starting watcher
676
+ await new Promise(resolve => setTimeout(resolve, 100));
677
+ replState.watcher = setupFileWatcher(resolvedAppDir, options);
678
+ // eslint-disable-next-line no-console
679
+ console.log(chalk.green('👀 File watching enabled'));
680
+ }
681
+ // Mark initialization as complete
682
+ replState.isInitializing = false;
683
+ // Give any async startup messages time to complete
684
+ await new Promise(resolve => setTimeout(resolve, 50));
685
+ // eslint-disable-next-line no-console
686
+ console.log(chalk.blue('💬 REPL ready - type "help" for help'));
687
+ // eslint-disable-next-line no-console
688
+ console.log(); // Extra newline for clean prompt appearance
689
+ // Create and expose helper functions globally
690
+ const helpers = createReplHelpers();
691
+ Object.assign(global, helpers);
692
+ // Start REPL loop
693
+ replState.rl.prompt();
694
+ replState.rl.on('line', (input) => {
695
+ void (async () => {
696
+ const trimmed = input.trim();
697
+ if (!trimmed) {
698
+ replState === null || replState === void 0 ? void 0 : replState.rl.prompt();
699
+ return;
700
+ }
701
+ try {
702
+ // Handle special commands without parentheses
703
+ if (trimmed === 'help' || trimmed === '?') {
704
+ helpers.utils.help();
705
+ replState === null || replState === void 0 ? void 0 : replState.rl.prompt();
706
+ return;
707
+ }
708
+ if (trimmed === 'exit' || trimmed === 'quit') {
709
+ helpers.utils.exit();
710
+ return;
711
+ }
712
+ if (trimmed === 'clear') {
713
+ helpers.utils.clear();
714
+ replState === null || replState === void 0 ? void 0 : replState.rl.prompt();
715
+ return;
716
+ }
717
+ if (trimmed === 'restart') {
718
+ await helpers.utils.restart();
719
+ replState === null || replState === void 0 ? void 0 : replState.rl.prompt();
720
+ return;
721
+ }
722
+ // Evaluate the input in the global context with helpers
723
+ const result = (await eval(trimmed));
724
+ // Handle promises
725
+ if (result && typeof result.then === 'function') {
726
+ try {
727
+ const resolved = await result;
728
+ if (resolved !== undefined && resolved !== '') {
729
+ // eslint-disable-next-line no-console
730
+ console.log(chalk.green('→'), resolved);
731
+ }
732
+ }
733
+ catch (error) {
734
+ // eslint-disable-next-line no-console
735
+ console.error(chalk.red('Promise rejected:'), error);
736
+ }
737
+ }
738
+ else if (result !== undefined && result !== '') {
739
+ // eslint-disable-next-line no-console
740
+ console.log(chalk.green('→'), result);
741
+ }
742
+ }
743
+ catch (error) {
744
+ // eslint-disable-next-line no-console
745
+ console.error(chalk.red('Error:'), error);
746
+ }
747
+ replState === null || replState === void 0 ? void 0 : replState.rl.prompt();
748
+ })();
749
+ });
750
+ replState.rl.on('close', () => {
751
+ cleanup();
752
+ process.exit(0);
753
+ });
754
+ }
755
+ catch (error) {
756
+ // eslint-disable-next-line no-console
757
+ console.error(chalk.red('❌ Failed to start REPL:'));
758
+ if (error instanceof Error) {
759
+ const nodeError = error;
760
+ if (nodeError.code === 'ENOENT') {
761
+ // eslint-disable-next-line no-console
762
+ console.error(chalk.red('File or directory not found:'), nodeError.path || 'unknown path');
763
+ // eslint-disable-next-line no-console
764
+ console.error(chalk.yellow('💡 Tip: Make sure the directory exists and contains a valid AgentLang application'));
765
+ }
766
+ else if (error.message.includes('app.config.json') || error.message.includes('package.json')) {
767
+ // eslint-disable-next-line no-console
768
+ console.error(chalk.red('Could not find required configuration files in the specified directory'));
769
+ // eslint-disable-next-line no-console
770
+ console.error(chalk.yellow('💡 Tip: Make sure you are pointing to a valid AgentLang application directory'));
771
+ }
772
+ else {
773
+ // eslint-disable-next-line no-console
774
+ console.error(chalk.red('Error:'), error.message);
775
+ }
776
+ }
777
+ else {
778
+ // eslint-disable-next-line no-console
779
+ console.error(chalk.red('Unknown error:'), error);
780
+ }
781
+ cleanup();
782
+ throw error;
783
+ }
784
+ }
785
+ //# sourceMappingURL=repl.js.map