@runflow-ai/cli 0.2.4 → 0.2.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.
Files changed (34) hide show
  1. package/dist/commands/agents/agents.command.js +244 -93
  2. package/dist/commands/agents/agents.command.js.map +1 -1
  3. package/dist/commands/login/login.command.js +23 -9
  4. package/dist/commands/login/login.command.js.map +1 -1
  5. package/dist/commands/prompts/prompts.command.js +13 -13
  6. package/dist/commands/prompts/prompts.command.js.map +1 -1
  7. package/dist/commands/test/test.command.d.ts +27 -0
  8. package/dist/commands/test/test.command.js +326 -0
  9. package/dist/commands/test/test.command.js.map +1 -0
  10. package/dist/commands/users/users.command.js +16 -19
  11. package/dist/commands/users/users.command.js.map +1 -1
  12. package/dist/common/api-client.js +4 -1
  13. package/dist/common/api-client.js.map +1 -1
  14. package/dist/common/banner.js +34 -1
  15. package/dist/common/banner.js.map +1 -1
  16. package/dist/common/config.d.ts +1 -1
  17. package/dist/common/config.js +42 -6
  18. package/dist/common/config.js.map +1 -1
  19. package/dist/common/help.d.ts +1 -1
  20. package/dist/common/help.js +1 -0
  21. package/dist/common/help.js.map +1 -1
  22. package/dist/common/logger.js +34 -1
  23. package/dist/common/logger.js.map +1 -1
  24. package/dist/common/system-check.d.ts +18 -0
  25. package/dist/common/system-check.js +118 -0
  26. package/dist/common/system-check.js.map +1 -0
  27. package/dist/common/ui.js +13 -4
  28. package/dist/common/ui.js.map +1 -1
  29. package/dist/common/validator.d.ts +13 -0
  30. package/dist/common/validator.js +191 -0
  31. package/dist/common/validator.js.map +1 -0
  32. package/dist/index.js +56 -3
  33. package/dist/index.js.map +1 -1
  34. package/package.json +8 -3
@@ -1,35 +1,74 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
2
18
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
19
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
20
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
21
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
22
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7
23
  };
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
8
41
  var __metadata = (this && this.__metadata) || function (k, v) {
9
42
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
43
  };
44
+ var __importDefault = (this && this.__importDefault) || function (mod) {
45
+ return (mod && mod.__esModule) ? mod : { "default": mod };
46
+ };
11
47
  Object.defineProperty(exports, "__esModule", { value: true });
12
48
  exports.AgentsCommand = void 0;
13
49
  const nest_commander_1 = require("nest-commander");
14
- const fs = require("fs");
15
- const path = require("path");
50
+ const fs = __importStar(require("fs"));
51
+ const path = __importStar(require("path"));
16
52
  const child_process_1 = require("child_process");
17
53
  const config_1 = require("../../common/config");
18
54
  const ui_1 = require("../../common/ui");
19
55
  const inquirer = require("inquirer");
20
56
  const logger_1 = require("../../common/logger");
21
57
  const api_client_1 = require("../../common/api-client");
58
+ const chalk_1 = __importDefault(require("chalk"));
59
+ const validator_1 = require("../../common/validator");
22
60
  const SENSITIVE_FILES = ['.env'];
23
- const IGNORE_DIRS = ['node_modules', 'dist', '.git'];
24
- const IGNORE_FILES = ['.DS_Store', '*.log', '*.lock', 'package-lock.json', '.runflow'];
61
+ const IGNORE_DIRS = ['node_modules', 'dist', '.git', '.runflow'];
62
+ const IGNORE_FILES = ['.DS_Store', 'package-lock.json'];
63
+ const IGNORE_PATTERNS = [/\.log$/, /\.lock$/, /\.tmp$/];
25
64
  async function showAgentActionMenu(agent) {
26
65
  const actions = [
27
- { name: 'šŸ“„ Clone repository (download)', value: 'clone' },
28
- { name: 'šŸ”„ Pull latest changes', value: 'pull' },
29
- { name: 'šŸš€ Duplicate agent on server', value: 'duplicate' },
30
- { name: '🚢 Deploy agent', value: 'deploy' },
31
- { name: 'šŸ—‘ļø Delete agent', value: 'delete' },
32
- { name: 'āŒ Cancel', value: 'cancel' }
66
+ { name: 'Clone repository (download)', value: 'clone' },
67
+ { name: 'Pull latest changes', value: 'pull' },
68
+ { name: 'Duplicate agent on server', value: 'duplicate' },
69
+ { name: 'Deploy agent', value: 'deploy' },
70
+ { name: 'Delete agent', value: 'delete' },
71
+ { name: 'Cancel', value: 'cancel' }
33
72
  ];
34
73
  const { action } = await inquirer.prompt([
35
74
  {
@@ -42,55 +81,75 @@ async function showAgentActionMenu(agent) {
42
81
  return action === 'cancel' ? null : action;
43
82
  }
44
83
  function sanitizeFileName(name) {
45
- return name.replace(/[<>:"/\\|?*]/g, '-').replace(/\s+/g, '-').toLowerCase();
84
+ const sanitized = name
85
+ .replace(/[<>:"/\\|?*]/g, '-')
86
+ .replace(/\s+/g, '-')
87
+ .replace(/-+/g, '-')
88
+ .replace(/^-|-$/g, '')
89
+ .toLowerCase();
90
+ return sanitized || 'agent';
46
91
  }
47
92
  async function detectAgentFromCurrentDirectory() {
48
93
  try {
49
94
  const currentDir = process.cwd();
50
- (0, logger_1.logVerbose)(`Checking for .runflow file in: ${currentDir}`);
51
- const runflowFile = path.join(currentDir, '.runflow');
95
+ (0, logger_1.logVerbose)(`Checking for .runflow/rf.json in: ${currentDir}`);
96
+ const runflowDir = path.join(currentDir, '.runflow');
97
+ const runflowFile = path.join(runflowDir, 'rf.json');
52
98
  if (fs.existsSync(runflowFile)) {
53
- (0, logger_1.logVerbose)(`Found .runflow file at: ${runflowFile}`);
99
+ (0, logger_1.logVerbose)(`Found .runflow/rf.json at: ${runflowFile}`);
54
100
  const content = fs.readFileSync(runflowFile, 'utf8');
55
- (0, logger_1.logVerbose)(`Raw .runflow content: ${content}`);
101
+ (0, logger_1.logVerbose)(`Raw rf.json content: ${content}`);
56
102
  const config = JSON.parse(content);
57
- (0, logger_1.logVerbose)(`Parsed .runflow config: ${JSON.stringify(config)}`);
103
+ (0, logger_1.logVerbose)(`Parsed rf.json config: ${JSON.stringify(config)}`);
58
104
  const agentId = config.agentId || null;
59
105
  if (agentId) {
60
- (0, logger_1.logVerbose)(`Detected agent ${agentId} from .runflow file`);
106
+ (0, logger_1.logVerbose)(`Detected agent ${agentId} from .runflow/rf.json`);
61
107
  }
62
108
  else {
63
- (0, logger_1.logVerbose)(`No agentId found in .runflow file`);
109
+ (0, logger_1.logVerbose)(`No agentId found in .runflow/rf.json`);
64
110
  }
65
111
  return agentId;
66
112
  }
67
- (0, logger_1.logVerbose)(`No .runflow file found in current directory: ${currentDir}`);
113
+ const oldRunflowFile = path.join(currentDir, '.runflow');
114
+ if (fs.existsSync(oldRunflowFile) && fs.statSync(oldRunflowFile).isFile()) {
115
+ (0, logger_1.logVerbose)(`Found legacy .runflow file at: ${oldRunflowFile}`);
116
+ const content = fs.readFileSync(oldRunflowFile, 'utf8');
117
+ const config = JSON.parse(content);
118
+ const agentId = config.agentId || null;
119
+ if (agentId) {
120
+ (0, logger_1.logVerbose)(`Detected agent ${agentId} from legacy .runflow file`);
121
+ }
122
+ return agentId;
123
+ }
124
+ (0, logger_1.logVerbose)(`No .runflow/rf.json found in current directory: ${currentDir}`);
68
125
  return null;
69
126
  }
70
127
  catch (error) {
71
- (0, logger_1.logVerbose)(`Error reading .runflow file: ${error}`);
128
+ (0, logger_1.logVerbose)(`Error reading .runflow/rf.json: ${error}`);
72
129
  return null;
73
130
  }
74
131
  }
75
132
  function dirToTree(dir, base = dir) {
76
133
  (0, logger_1.logVerbose)(`šŸ“ Scanning directory: ${dir}`);
77
134
  const result = fs.readdirSync(dir, { withFileTypes: true }).reduce((acc, entry) => {
135
+ const fullPath = path.join(dir, entry.name);
136
+ const relPath = path.relative(base, fullPath).replace(/\\/g, '/');
78
137
  if (IGNORE_DIRS.includes(entry.name) ||
79
138
  SENSITIVE_FILES.includes(entry.name) ||
80
- IGNORE_FILES.some((pattern) => entry.name.includes(pattern.replace('*', '')))) {
81
- (0, logger_1.logVerbose)(`ā­ļø Ignoring: ${entry.name} (matches ignore rules)`);
139
+ IGNORE_FILES.includes(entry.name) ||
140
+ IGNORE_PATTERNS.some(pattern => pattern.test(entry.name))) {
141
+ return acc;
142
+ }
143
+ if (entry.name === '.runflow') {
82
144
  return acc;
83
145
  }
84
- const fullPath = path.join(dir, entry.name);
85
146
  if (entry.isDirectory()) {
86
- (0, logger_1.logVerbose)(`šŸ“‚ Processing directory: ${entry.name}`);
87
147
  acc.push(...dirToTree(fullPath, base));
88
148
  }
89
149
  else if (entry.isFile()) {
90
150
  const relPath = path.relative(base, fullPath).replace(/\\/g, '/');
91
151
  try {
92
152
  const content = fs.readFileSync(fullPath, 'utf8');
93
- (0, logger_1.logVerbose)(`šŸ“„ Adding file: ${relPath} (${content.length} chars)`);
94
153
  acc.push({ path: relPath, mode: '100644', type: 'blob', content });
95
154
  }
96
155
  catch (error) {
@@ -104,14 +163,23 @@ function dirToTree(dir, base = dir) {
104
163
  }
105
164
  let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
106
165
  async performDeploy(targetAgentId, apiClient, data) {
166
+ const validation = (0, validator_1.validateForDeploy)();
167
+ if (!validation.isValid) {
168
+ console.error(chalk_1.default.red('\nāŒ Deploy validation failed!'));
169
+ validation.errors.forEach(error => {
170
+ console.error(chalk_1.default.red(` • ${error}`));
171
+ });
172
+ console.error(chalk_1.default.gray('\nšŸ“š Documentation: https://docs.runflow.ai\n'));
173
+ return;
174
+ }
107
175
  (0, logger_1.logVerbose)(`Deploying agent ${targetAgentId} with local changes...`);
108
176
  (0, logger_1.logVerbose)(`Current directory: ${process.cwd()}`);
109
177
  const baseRepo = path.basename(process.cwd());
110
178
  const { config } = (0, config_1.getValidatedConfig)();
111
179
  const repo = `${config.tenantId}-${baseRepo}`;
112
180
  const tree = dirToTree(process.cwd()).filter((item) => Boolean(item.path));
113
- const deletedFiles = this.getDeletedFiles();
114
- const fullTree = [...tree, ...deletedFiles];
181
+ const deletedFilesFromGit = this.getDeletedFiles();
182
+ const fullTree = [...tree, ...deletedFilesFromGit];
115
183
  const defaultPayload = {
116
184
  repo,
117
185
  message: 'deploy with local changes',
@@ -121,32 +189,49 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
121
189
  const payload = data
122
190
  ? JSON.parse(data)
123
191
  : defaultPayload;
124
- (0, logger_1.logVerbose)(`šŸ“¦ Deploy Summary:`);
125
- (0, logger_1.logVerbose)(` Files to send: ${payload.tree.length}`);
126
- (0, logger_1.logVerbose)(` Payload size: ${JSON.stringify(payload).length} bytes`);
127
- (0, logger_1.logVerbose)(` Repository: ${payload.repo}`);
128
- (0, logger_1.logVerbose)(` Branch: ${payload.branch}`);
129
- if (payload.tree.length > 0) {
130
- const normalFiles = payload.tree.filter(item => !item.deleted);
131
- const deletedFiles = payload.tree.filter(item => item.deleted);
132
- if (normalFiles.length > 0) {
133
- (0, logger_1.logVerbose)(`šŸ“‹ Files being deployed:`);
134
- normalFiles.forEach((item, index) => {
135
- (0, logger_1.logVerbose)(` ${index + 1}. ${item.path} (${item.content?.length || 0} chars)`);
136
- });
137
- }
138
- if (deletedFiles.length > 0) {
139
- (0, logger_1.logVerbose)(`šŸ—‘ļø Files being deleted:`);
140
- deletedFiles.forEach((item, index) => {
141
- (0, logger_1.logVerbose)(` ${index + 1}. ${item.path} (deleted)`);
142
- });
192
+ const normalFiles = payload.tree.filter(item => !item.deleted);
193
+ const deletedFiles = payload.tree.filter(item => item.deleted);
194
+ console.log(chalk_1.default.cyan.bold('\nšŸ“¦ Deploy Preview:'));
195
+ console.log(chalk_1.default.gray(`Repository: ${payload.repo}`));
196
+ console.log(chalk_1.default.gray(`Files: ${normalFiles.length} to deploy, ${deletedFiles.length} to delete`));
197
+ if (normalFiles.length > 0) {
198
+ console.log(chalk_1.default.green('\nšŸ“„ Files to deploy:'));
199
+ normalFiles.slice(0, 10).forEach((item, index) => {
200
+ const size = item.content?.length || 0;
201
+ const sizeStr = size > 1024 ? `${Math.round(size / 1024)}KB` : `${size}B`;
202
+ console.log(chalk_1.default.gray(` ${index + 1}.`), chalk_1.default.white(item.path), chalk_1.default.gray(`(${sizeStr})`));
203
+ });
204
+ if (normalFiles.length > 10) {
205
+ console.log(chalk_1.default.gray(` ... and ${normalFiles.length - 10} more files`));
143
206
  }
144
207
  }
145
- else {
146
- (0, logger_1.logVerbose)(`āš ļø WARNING: No files to deploy!`);
208
+ if (deletedFiles.length > 0) {
209
+ console.log(chalk_1.default.red('\nšŸ—‘ļø Files to delete:'));
210
+ deletedFiles.forEach((item, index) => {
211
+ console.log(chalk_1.default.gray(` ${index + 1}.`), chalk_1.default.white(item.path));
212
+ });
213
+ }
214
+ if (payload.tree.length === 0) {
215
+ console.log(chalk_1.default.yellow('\nāš ļø No files to deploy!'));
216
+ return;
147
217
  }
218
+ const { confirm } = await inquirer.prompt([
219
+ {
220
+ type: 'confirm',
221
+ name: 'confirm',
222
+ message: `Deploy ${normalFiles.length} files to agent ${targetAgentId}?`,
223
+ default: true
224
+ }
225
+ ]);
226
+ if (!confirm) {
227
+ console.log(chalk_1.default.yellow('Deploy cancelled'));
228
+ return;
229
+ }
230
+ console.log(chalk_1.default.blue('\nšŸš€ Deploying...'));
148
231
  const res = await apiClient.patch(`/agents/${targetAgentId}/deploy`, payload);
149
- (0, logger_1.logSuccess)(`Deployed agent with local changes`);
232
+ console.log(chalk_1.default.green.bold('\nāœ… Deploy Successful!'));
233
+ console.log(chalk_1.default.gray(`šŸ“¦ ${normalFiles.length} files deployed`));
234
+ console.log(chalk_1.default.gray(`šŸ• ${new Date().toLocaleTimeString()}`));
150
235
  try {
151
236
  (0, logger_1.logVerbose)(`Creating commit for deployed changes...`);
152
237
  const currentDir = process.cwd();
@@ -202,13 +287,63 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
202
287
  const agentName = sanitizeFileName(agent.name || agent.id);
203
288
  switch (action) {
204
289
  case 'clone': {
205
- (0, logger_1.logVerbose)(`Cloning agent ${agentId} repository...`);
290
+ try {
291
+ (0, child_process_1.execSync)('git --version', { stdio: 'pipe', timeout: 3000 });
292
+ }
293
+ catch (error) {
294
+ console.log(chalk_1.default.red('Git is required for cloning agents'));
295
+ console.log(chalk_1.default.gray('Install Git: https://git-scm.com\n'));
296
+ return;
297
+ }
298
+ console.log(chalk_1.default.blue('Cloning agent repository...'));
206
299
  const res = await apiClient.get(`/agents/${agentId}/clone`);
207
300
  const tree = res.data;
208
301
  (0, logger_1.logVerbose)(`Received ${tree.length} items from API`);
209
302
  const gitFiles = tree.filter(item => item.path.startsWith('.git'));
210
303
  (0, logger_1.logVerbose)(`Found ${gitFiles.length} .git files: ${gitFiles.map(f => f.path).join(', ')}`);
211
- const dir = agentName;
304
+ let dir = agentName;
305
+ if (fs.existsSync(dir)) {
306
+ console.log(chalk_1.default.yellow(`\n⚠ Directory "${dir}" already exists`));
307
+ const { action } = await inquirer.prompt([
308
+ {
309
+ type: 'list',
310
+ name: 'action',
311
+ message: 'What would you like to do?',
312
+ choices: [
313
+ { name: 'Overwrite existing directory', value: 'overwrite' },
314
+ { name: 'Clone with different name', value: 'rename' },
315
+ { name: 'Cancel', value: 'cancel' }
316
+ ]
317
+ }
318
+ ]);
319
+ if (action === 'cancel') {
320
+ console.log(chalk_1.default.gray('Clone cancelled'));
321
+ return;
322
+ }
323
+ if (action === 'rename') {
324
+ const { newName } = await inquirer.prompt([
325
+ {
326
+ type: 'input',
327
+ name: 'newName',
328
+ message: 'Enter new directory name:',
329
+ default: `${agentName}-copy`,
330
+ validate: (input) => {
331
+ if (!input.trim())
332
+ return 'Directory name cannot be empty';
333
+ if (fs.existsSync(input.trim()))
334
+ return `Directory "${input.trim()}" already exists`;
335
+ return true;
336
+ }
337
+ }
338
+ ]);
339
+ dir = newName.trim();
340
+ console.log(chalk_1.default.blue(`Using directory name: ${dir}`));
341
+ }
342
+ else if (action === 'overwrite') {
343
+ fs.rmSync(dir, { recursive: true, force: true });
344
+ console.log(chalk_1.default.blue('Removed existing directory'));
345
+ }
346
+ }
212
347
  fs.mkdirSync(dir, { recursive: true });
213
348
  const gitRefFiles = {};
214
349
  const regularFiles = tree.filter(item => {
@@ -261,20 +396,27 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
261
396
  catch (error) {
262
397
  (0, logger_1.logVerbose)(`āŒ Error initializing git: ${error}`);
263
398
  }
264
- const runflowPath = path.join(dir, '.runflow');
399
+ const runflowPath = path.join(dir, '.runflow', 'rf.json');
265
400
  if (fs.existsSync(runflowPath)) {
266
- (0, logger_1.logVerbose)(`āœ… .runflow file provided by API for deploy operations`);
401
+ (0, logger_1.logVerbose)(`āœ… .runflow/rf.json provided by API for deploy operations`);
267
402
  }
268
403
  else {
269
- (0, logger_1.logVerbose)(`āš ļø No .runflow file found - deploy may not work`);
404
+ (0, logger_1.logVerbose)(`āš ļø No .runflow/rf.json found - deploy may not work`);
270
405
  }
271
- (0, logger_1.logSuccess)(`Repository cloned to ${dir}/`);
406
+ console.log(chalk_1.default.green.bold(`\nāœ“ Repository cloned to ${dir}/`));
407
+ console.log(chalk_1.default.cyan.bold('\nNext Steps:'));
408
+ console.log(chalk_1.default.gray('1.'), chalk_1.default.white(`cd ${dir}`));
409
+ console.log(chalk_1.default.gray('2.'), chalk_1.default.white('npm install'));
410
+ console.log(chalk_1.default.gray('3.'), chalk_1.default.white('rf test'), chalk_1.default.gray('# Start test interface'));
411
+ console.log(chalk_1.default.gray('4.'), chalk_1.default.white('rf deploy'), chalk_1.default.gray('# Deploy changes back'));
412
+ console.log(chalk_1.default.cyan.bold('\nQuick Start:'));
413
+ console.log(chalk_1.default.white(`cd ${dir} && npm install && rf test`));
272
414
  break;
273
415
  }
274
416
  case 'pull': {
275
417
  const detectedAgentId = await detectAgentFromCurrentDirectory();
276
418
  if (!detectedAgentId) {
277
- (0, logger_1.logError)('āŒ Pull requires being in a cloned agent directory with .runflow file.');
419
+ (0, logger_1.logError)('āŒ Pull requires being in a cloned agent directory with .runflow/rf.json.');
278
420
  (0, logger_1.logError)('šŸ’” Either:');
279
421
  (0, logger_1.logError)(' 1. Navigate to a cloned agent directory and try again');
280
422
  (0, logger_1.logError)(' 2. Use "Clone repository" first to download the agent');
@@ -357,7 +499,7 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
357
499
  case 'deploy': {
358
500
  const detectedAgentId = await detectAgentFromCurrentDirectory();
359
501
  if (!detectedAgentId) {
360
- (0, logger_1.logError)('āŒ Deploy from menu requires being in a cloned agent directory with .runflow file.');
502
+ (0, logger_1.logError)('āŒ Deploy from menu requires being in a cloned agent directory with .runflow/rf.json.');
361
503
  (0, logger_1.logError)('šŸ’” Either:');
362
504
  (0, logger_1.logError)(' 1. Navigate to a cloned agent directory and try again');
363
505
  (0, logger_1.logError)(' 2. Use "Clone repository" first to download the agent');
@@ -394,6 +536,18 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
394
536
  }
395
537
  async run(inputs, options) {
396
538
  const [action, data] = inputs;
539
+ if (!action) {
540
+ console.log(chalk_1.default.cyan.bold('Agents Management'));
541
+ console.log(chalk_1.default.gray('Manage your AI agents\n'));
542
+ console.log(chalk_1.default.cyan('Available actions:'));
543
+ console.log(chalk_1.default.gray(' rf agents list # List and select agents'));
544
+ console.log(chalk_1.default.gray(' rf agents clone # Download agent code'));
545
+ console.log(chalk_1.default.gray(' rf agents deploy # Upload your changes'));
546
+ console.log(chalk_1.default.gray(' rf agents get # Show current agent'));
547
+ console.log(chalk_1.default.cyan('\nQuick start:'));
548
+ console.log(chalk_1.default.white(' rf agents list'));
549
+ return;
550
+ }
397
551
  const actions = [
398
552
  'list',
399
553
  'get',
@@ -405,24 +559,6 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
405
559
  'duplicate',
406
560
  'deploy',
407
561
  ];
408
- if (!action) {
409
- (0, logger_1.log)('\nUsage: rf agents <action> [data]\n');
410
- (0, logger_1.log)('Actions:');
411
- (0, logger_1.log)(' list List agents and select active one');
412
- (0, logger_1.log)(' get Display active agent');
413
- (0, logger_1.log)(' create <json> Create agent');
414
- (0, logger_1.log)(' update <json> Update active agent');
415
- (0, logger_1.log)(' delete Remove active agent');
416
- (0, logger_1.log)(' clone Clone agent repository (download)');
417
- (0, logger_1.log)(' pull Pull latest changes (overwrites local)');
418
- (0, logger_1.log)(' duplicate Duplicate agent on server');
419
- (0, logger_1.log)(' deploy Deploy agent with local changes\n');
420
- (0, logger_1.log)('Options:');
421
- (0, logger_1.log)(' --api-key <key> API key override');
422
- (0, logger_1.log)(' --api <url> API URL override');
423
- (0, logger_1.log)(' --help, -h Show this help\n');
424
- return;
425
- }
426
562
  if (!actions.includes(action)) {
427
563
  (0, logger_1.logError)(config_1.ERROR_MESSAGES.INVALID_ACTION(action, actions));
428
564
  return;
@@ -433,14 +569,21 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
433
569
  const agentId = config.agentId;
434
570
  switch (action) {
435
571
  case 'list': {
436
- (0, logger_1.logVerbose)('Fetching agents...');
572
+ console.log(chalk_1.default.blue('Fetching agents...'));
437
573
  const res = await apiClient.get('/agents');
438
574
  const agents = res.data.data ?? res.data;
575
+ if (!agents || agents.length === 0) {
576
+ console.log(chalk_1.default.yellow('No agents found'));
577
+ console.log(chalk_1.default.gray('Create your first agent in the dashboard'));
578
+ return;
579
+ }
580
+ console.log(chalk_1.default.cyan.bold(`\nFound ${agents.length} agents:`));
439
581
  const selected = await (0, ui_1.selectItem)(agents, 'Select an agent:');
440
582
  (0, config_1.saveConfig)({ agentId: selected.id });
583
+ console.log(chalk_1.default.green(`\nāœ“ Selected: ${selected.name}`));
441
584
  const selectedAction = await showAgentActionMenu(selected);
442
585
  if (!selectedAction) {
443
- (0, logger_1.logSuccess)('Operation cancelled');
586
+ console.log(chalk_1.default.gray('Operation cancelled'));
444
587
  return;
445
588
  }
446
589
  await this.executeAction(selectedAction, selected, apiClient);
@@ -448,12 +591,19 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
448
591
  }
449
592
  case 'get': {
450
593
  if (!agentId) {
451
- (0, logger_1.logError)(config_1.ERROR_MESSAGES.AGENT_NOT_SELECTED);
594
+ console.log(chalk_1.default.red('No agent selected'));
595
+ console.log(chalk_1.default.gray('Run: rf agents list'));
452
596
  return;
453
597
  }
454
- (0, logger_1.logVerbose)(`Fetching agent ${agentId}...`);
598
+ console.log(chalk_1.default.blue(`Fetching agent details...`));
455
599
  const res = await apiClient.get(`/agents/${agentId}`);
456
- (0, logger_1.logJson)([res.data]);
600
+ console.log(chalk_1.default.cyan.bold('\nAgent Details:'));
601
+ console.log(chalk_1.default.gray(`Name: ${res.data.name}`));
602
+ console.log(chalk_1.default.gray(`ID: ${res.data.id}`));
603
+ console.log(chalk_1.default.gray(`Status: ${res.data.status || 'active'}`));
604
+ if (res.data.updatedAt) {
605
+ console.log(chalk_1.default.gray(`Updated: ${new Date(res.data.updatedAt).toLocaleString()}`));
606
+ }
457
607
  break;
458
608
  }
459
609
  case 'create': {
@@ -497,7 +647,11 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
497
647
  }
498
648
  (0, logger_1.logVerbose)(`Cloning agent ${agentId} repository...`);
499
649
  const agentRes = await apiClient.get(`/agents/${agentId}`);
500
- const agentName = sanitizeFileName(agentRes.data.name || agentId);
650
+ const originalName = agentRes.data.name || agentId;
651
+ const agentName = sanitizeFileName(originalName);
652
+ if (originalName !== agentName) {
653
+ console.log(chalk_1.default.gray(`Directory name: "${originalName}" → "${agentName}"`));
654
+ }
501
655
  const res = await apiClient.get(`/agents/${agentId}/clone`);
502
656
  const tree = res.data;
503
657
  (0, logger_1.logVerbose)(`Received ${tree.length} items from API`);
@@ -564,6 +718,13 @@ let AgentsCommand = class AgentsCommand extends nest_commander_1.CommandRunner {
564
718
  (0, logger_1.logVerbose)(`āš ļø No .runflow file found - deploy may not work`);
565
719
  }
566
720
  (0, logger_1.logSuccess)(`Repository cloned to ${dir}/`);
721
+ console.log(chalk_1.default.cyan.bold('\nšŸš€ Next Steps:'));
722
+ console.log(chalk_1.default.gray('1.'), chalk_1.default.white(`cd ${dir}`));
723
+ console.log(chalk_1.default.gray('2.'), chalk_1.default.white('npm install'));
724
+ console.log(chalk_1.default.gray('3.'), chalk_1.default.white('rf test'), chalk_1.default.gray('# Start test interface'));
725
+ console.log(chalk_1.default.gray('4.'), chalk_1.default.white('rf deploy'), chalk_1.default.gray('# Deploy changes back'));
726
+ console.log(chalk_1.default.cyan.bold('\nšŸ’” Quick Start:'));
727
+ console.log(chalk_1.default.gray(`cd ${dir} && npm install && rf test`));
567
728
  break;
568
729
  }
569
730
  case 'pull': {
@@ -690,18 +851,8 @@ exports.AgentsCommand = AgentsCommand = __decorate([
690
851
  (0, nest_commander_1.Command)({
691
852
  name: 'agents',
692
853
  aliases: ['agent'],
693
- arguments: '<action> [data]',
694
- description: 'Manage AI agents.\n' +
695
- 'Actions:\n' +
696
- ' list List agents and select active one\n' +
697
- ' get Display active agent\n' +
698
- ' create <json> Create agent\n' +
699
- ' update <json> Update active agent\n' +
700
- ' delete Remove active agent\n' +
701
- ' clone Clone agent repository (download)\n' +
702
- ' pull Pull latest changes (overwrites local)\n' +
703
- ' duplicate Duplicate agent on server\n' +
704
- ' deploy Deploy agent with local changes',
854
+ arguments: '[action] [data]',
855
+ description: 'šŸ¤– Manage AI agents (run without action for help)',
705
856
  })
706
857
  ], AgentsCommand);
707
858
  //# sourceMappingURL=agents.command.js.map