@agentforge/cli 0.16.3 → 0.16.5

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/dist/index.js CHANGED
@@ -75,6 +75,30 @@ var Logger = class {
75
75
  }
76
76
  };
77
77
  var logger = new Logger();
78
+
79
+ // src/utils/command-errors.ts
80
+ function getErrorMessage(error) {
81
+ if (error instanceof Error) {
82
+ return error.message;
83
+ }
84
+ if (typeof error === "string") {
85
+ return error;
86
+ }
87
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
88
+ return error.message;
89
+ }
90
+ return String(error);
91
+ }
92
+ function exitWithCommandError(error, options = {}) {
93
+ if (options.spinnerFailureText) {
94
+ logger.failSpinner(options.spinnerFailureText);
95
+ }
96
+ if (options.logError !== false) {
97
+ const message = options.message ?? getErrorMessage(error);
98
+ logger.error(options.prefix ? `${options.prefix}: ${message}` : message);
99
+ }
100
+ process.exit(1);
101
+ }
78
102
  async function promptProjectSetup(defaults = {}) {
79
103
  return inquirer.prompt([
80
104
  {
@@ -434,13 +458,11 @@ async function createCommand(projectName, options) {
434
458
  try {
435
459
  logger.header("\u{1F680} Create AgentForge Project");
436
460
  if (!projectName) {
437
- logger.error("Project name is required");
438
- process.exit(1);
461
+ return exitWithCommandError("Project name is required");
439
462
  }
440
463
  const targetPath = path12.join(process.cwd(), projectName);
441
464
  if (!await isEmptyDir(targetPath)) {
442
- logger.error(`Directory ${projectName} already exists and is not empty`);
443
- process.exit(1);
465
+ return exitWithCommandError(`Directory ${projectName} already exists and is not empty`);
444
466
  }
445
467
  const answers = await promptProjectSetup({
446
468
  projectName,
@@ -483,7 +505,7 @@ async function createCommand(projectName, options) {
483
505
  try {
484
506
  await installDependencies(targetPath, answers.packageManager);
485
507
  logger.succeedSpinner("Dependencies installed");
486
- } catch (error) {
508
+ } catch {
487
509
  logger.failSpinner("Failed to install dependencies");
488
510
  logger.warn("You can install them manually later");
489
511
  }
@@ -494,7 +516,7 @@ async function createCommand(projectName, options) {
494
516
  await initGitRepository(targetPath);
495
517
  await createInitialCommit(targetPath);
496
518
  logger.succeedSpinner("Git repository initialized");
497
- } catch (error) {
519
+ } catch {
498
520
  logger.failSpinner("Failed to initialize git");
499
521
  logger.warn("You can initialize it manually later");
500
522
  }
@@ -510,8 +532,7 @@ async function createCommand(projectName, options) {
510
532
  logger.newLine();
511
533
  logger.info("Happy coding! \u{1F389}");
512
534
  } catch (error) {
513
- logger.error(`Failed to create project: ${error.message}`);
514
- process.exit(1);
535
+ return exitWithCommandError(error, { prefix: "Failed to create project" });
515
536
  }
516
537
  }
517
538
 
@@ -531,9 +552,9 @@ async function devCommand(options) {
531
552
  await runScript(cwd, "dev", packageManager);
532
553
  logger.succeedSpinner("Development server started");
533
554
  } catch (error) {
534
- logger.failSpinner("Failed to start development server");
535
- logger.error(error.message);
536
- process.exit(1);
555
+ return exitWithCommandError(error, {
556
+ spinnerFailureText: "Failed to start development server"
557
+ });
537
558
  }
538
559
  }
539
560
 
@@ -559,9 +580,7 @@ async function buildCommand(options) {
559
580
  logger.newLine();
560
581
  logger.success("\u2728 Production build ready!");
561
582
  } catch (error) {
562
- logger.failSpinner("Build failed");
563
- logger.error(error.message);
564
- process.exit(1);
583
+ return exitWithCommandError(error, { spinnerFailureText: "Build failed" });
565
584
  }
566
585
  }
567
586
 
@@ -587,9 +606,7 @@ async function testCommand(options) {
587
606
  await runScript(cwd, script, packageManager);
588
607
  logger.succeedSpinner("Tests completed");
589
608
  } catch (error) {
590
- logger.failSpinner("Tests failed");
591
- logger.error(error.message);
592
- process.exit(1);
609
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
593
610
  }
594
611
  }
595
612
 
@@ -606,7 +623,7 @@ async function lintCommand(options) {
606
623
  try {
607
624
  await runScript(cwd, options.fix ? "lint:fix" : "lint", packageManager);
608
625
  logger.succeedSpinner("Linting completed");
609
- } catch (error) {
626
+ } catch {
610
627
  logger.failSpinner("Linting found issues");
611
628
  if (!options.fix) {
612
629
  logger.info("Run with --fix to automatically fix issues");
@@ -617,15 +634,14 @@ async function lintCommand(options) {
617
634
  try {
618
635
  await runScript(cwd, "format", packageManager);
619
636
  logger.succeedSpinner("Formatting completed");
620
- } catch (error) {
637
+ } catch {
621
638
  logger.failSpinner("Formatting failed");
622
639
  }
623
640
  }
624
641
  logger.newLine();
625
642
  logger.success("\u2728 Code quality check completed!");
626
643
  } catch (error) {
627
- logger.error(error.message);
628
- process.exit(1);
644
+ return exitWithCommandError(error);
629
645
  }
630
646
  }
631
647
  async function agentCreateCommand(name, options) {
@@ -666,8 +682,7 @@ async function agentCreateCommand(name, options) {
666
682
  answers.generateTests ? `Run ${chalk4.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
667
683
  ].filter(Boolean));
668
684
  } catch (error) {
669
- logger.error(`Failed to create agent: ${error.message}`);
670
- process.exit(1);
685
+ return exitWithCommandError(error, { prefix: "Failed to create agent" });
671
686
  }
672
687
  }
673
688
  function generateAgentContent(name, pattern, description) {
@@ -850,8 +865,7 @@ async function agentCreateReusableCommand(name, options) {
850
865
  logger.newLine();
851
866
  logger.info(chalk4.gray("\u{1F4A1} Tip: See examples/vertical-agents/ for reference implementations"));
852
867
  } catch (error) {
853
- logger.error(`Failed to create reusable agent: ${error.message}`);
854
- process.exit(1);
868
+ return exitWithCommandError(error, { prefix: "Failed to create reusable agent" });
855
869
  }
856
870
  }
857
871
  function kebabToPascal(str) {
@@ -899,8 +913,7 @@ async function agentListCommand(options) {
899
913
  logger.info(`Use ${chalk4.cyan("--verbose")} for more details`);
900
914
  }
901
915
  } catch (error) {
902
- logger.error(`Failed to list agents: ${error.message}`);
903
- process.exit(1);
916
+ return exitWithCommandError(error, { prefix: "Failed to list agents" });
904
917
  }
905
918
  }
906
919
  function extractPattern(content) {
@@ -924,7 +937,7 @@ async function agentTestCommand(name, options) {
924
937
  if (!await pathExists(testFile)) {
925
938
  logger.error(`Test file not found: ${testFile}`);
926
939
  logger.info(`Create tests with: ${chalk4.cyan(`agentforge agent:create ${name} --test`)}`);
927
- process.exit(1);
940
+ return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
928
941
  }
929
942
  logger.info(`Testing agent: ${chalk4.cyan(name)}`);
930
943
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
@@ -936,9 +949,7 @@ async function agentTestCommand(name, options) {
936
949
  await runScript(cwd, testCommand2, packageManager);
937
950
  logger.succeedSpinner("Tests completed");
938
951
  } catch (error) {
939
- logger.failSpinner("Tests failed");
940
- logger.error(error.message);
941
- process.exit(1);
952
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
942
953
  }
943
954
  }
944
955
  async function agentDeployCommand(name, options) {
@@ -972,10 +983,11 @@ async function agentDeployCommand(name, options) {
972
983
  logger.newLine();
973
984
  logger.info(chalk4.dim("For detailed deployment guides, see:"));
974
985
  logger.info(chalk4.dim("https://tvscoundrel.github.io/agentforge/guide/advanced/deployment"));
975
- process.exit(1);
986
+ return exitWithCommandError("Automated agent deployment is not yet implemented", {
987
+ logError: false
988
+ });
976
989
  } catch (error) {
977
- logger.error(error.message);
978
- process.exit(1);
990
+ return exitWithCommandError(error);
979
991
  }
980
992
  }
981
993
  async function toolCreateCommand(name, options) {
@@ -1016,8 +1028,7 @@ async function toolCreateCommand(name, options) {
1016
1028
  ];
1017
1029
  logger.list(nextSteps.filter(Boolean));
1018
1030
  } catch (error) {
1019
- logger.error(`Failed to create tool: ${error.message}`);
1020
- process.exit(1);
1031
+ return exitWithCommandError(error, { prefix: "Failed to create tool" });
1021
1032
  }
1022
1033
  }
1023
1034
  function generateToolContent(name, category, description) {
@@ -1165,8 +1176,7 @@ async function toolListCommand(options) {
1165
1176
  logger.info(`Use ${chalk4.cyan("--verbose")} for more details`);
1166
1177
  }
1167
1178
  } catch (error) {
1168
- logger.error(`Failed to list tools: ${error.message}`);
1169
- process.exit(1);
1179
+ return exitWithCommandError(error, { prefix: "Failed to list tools" });
1170
1180
  }
1171
1181
  }
1172
1182
  function extractCategory(content) {
@@ -1185,7 +1195,7 @@ async function toolTestCommand(name, options) {
1185
1195
  if (!await pathExists(testFile)) {
1186
1196
  logger.error(`Test file not found: ${testFile}`);
1187
1197
  logger.info(`Create tests with: ${chalk4.cyan(`agentforge tool:create ${name} --test`)}`);
1188
- process.exit(1);
1198
+ return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
1189
1199
  }
1190
1200
  logger.info(`Testing tool: ${chalk4.cyan(name)}`);
1191
1201
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
@@ -1197,9 +1207,7 @@ async function toolTestCommand(name, options) {
1197
1207
  await runScript(cwd, testCommand2, packageManager);
1198
1208
  logger.succeedSpinner("Tests completed");
1199
1209
  } catch (error) {
1200
- logger.failSpinner("Tests failed");
1201
- logger.error(error.message);
1202
- process.exit(1);
1210
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
1203
1211
  }
1204
1212
  }
1205
1213
  async function toolPublishCommand(name, options) {
@@ -1221,9 +1229,10 @@ async function toolPublishCommand(name, options) {
1221
1229
  await runScript(toolPath, "test", packageManager);
1222
1230
  logger.succeedSpinner("Tests passed");
1223
1231
  } catch (error) {
1224
- logger.failSpinner("Tests failed");
1225
- logger.error("Cannot publish tool with failing tests");
1226
- process.exit(1);
1232
+ return exitWithCommandError(error, {
1233
+ spinnerFailureText: "Tests failed",
1234
+ message: "Cannot publish tool with failing tests"
1235
+ });
1227
1236
  }
1228
1237
  } else {
1229
1238
  logger.info("\u26A0\uFE0F Skipping tests (no test script found)");
@@ -1234,8 +1243,7 @@ async function toolPublishCommand(name, options) {
1234
1243
  await runScript(toolPath, "build", packageManager);
1235
1244
  logger.succeedSpinner("Build completed");
1236
1245
  } catch (error) {
1237
- logger.failSpinner("Build failed");
1238
- process.exit(1);
1246
+ return exitWithCommandError(error, { spinnerFailureText: "Build failed" });
1239
1247
  }
1240
1248
  } else {
1241
1249
  logger.info("\u26A0\uFE0F Skipping build (no build script found)");
@@ -1253,20 +1261,23 @@ async function toolPublishCommand(name, options) {
1253
1261
  logger.succeedSpinner("Published to npm");
1254
1262
  }
1255
1263
  } catch (error) {
1264
+ const errorMessage = getErrorMessage(error);
1256
1265
  logger.failSpinner("Publishing failed");
1257
- if (error.message.includes("ENEEDAUTH") || error.message.includes("E401")) {
1266
+ if (errorMessage.includes("ENEEDAUTH") || errorMessage.includes("E401")) {
1258
1267
  logger.error("Not authenticated with npm");
1259
1268
  logger.info("Run: npm login");
1260
- } else if (error.message.includes("E403")) {
1269
+ } else if (errorMessage.includes("E403")) {
1261
1270
  logger.error("Permission denied - you may not have access to publish this package");
1262
1271
  logger.info("Check package name and npm organization permissions");
1263
- } else if (error.message.includes("EPUBLISHCONFLICT") || error.message.includes("E409")) {
1272
+ } else if (errorMessage.includes("EPUBLISHCONFLICT") || errorMessage.includes("E409")) {
1264
1273
  logger.error("Version already published");
1265
1274
  logger.info("Update the version in package.json before publishing");
1266
1275
  } else {
1267
- logger.error(error.message);
1276
+ logger.error(errorMessage);
1268
1277
  }
1269
- process.exit(1);
1278
+ return exitWithCommandError(error, {
1279
+ logError: false
1280
+ });
1270
1281
  }
1271
1282
  logger.newLine();
1272
1283
  if (options.dryRun) {
@@ -1280,9 +1291,7 @@ async function toolPublishCommand(name, options) {
1280
1291
  logger.info("Users can now install with: npm install " + name);
1281
1292
  }
1282
1293
  } catch (error) {
1283
- logger.failSpinner("Publishing failed");
1284
- logger.error(error.message);
1285
- process.exit(1);
1294
+ return exitWithCommandError(error, { spinnerFailureText: "Publishing failed" });
1286
1295
  }
1287
1296
  }
1288
1297
  async function resolveToolPath(name) {
@@ -1335,29 +1344,25 @@ async function resolveToolPath(name) {
1335
1344
  "Providing a path to the tool package directory",
1336
1345
  "Have the tool in a standard location (./tools/<name>, ./packages/<name>)"
1337
1346
  ]);
1338
- process.exit(1);
1347
+ return exitWithCommandError(`Could not find tool package: ${name}`, { logError: false });
1339
1348
  }
1340
1349
  async function validateToolPath(toolPath, expectedName) {
1341
1350
  if (!await fs.pathExists(toolPath)) {
1342
- logger.error(`Tool directory not found: ${toolPath}`);
1343
- process.exit(1);
1351
+ return exitWithCommandError(`Tool directory not found: ${toolPath}`);
1344
1352
  }
1345
1353
  const packageJsonPath = path12.join(toolPath, "package.json");
1346
1354
  if (!await fs.pathExists(packageJsonPath)) {
1347
- logger.error(`package.json not found in: ${toolPath}`);
1348
1355
  logger.info("Tool packages must have a package.json file");
1349
- process.exit(1);
1356
+ return exitWithCommandError(`package.json not found in: ${toolPath}`);
1350
1357
  }
1351
1358
  let packageJson;
1352
1359
  try {
1353
1360
  packageJson = await fs.readJson(packageJsonPath);
1354
1361
  } catch (error) {
1355
- logger.error(`Failed to read package.json: ${error.message}`);
1356
- process.exit(1);
1362
+ return exitWithCommandError(error, { prefix: "Failed to read package.json" });
1357
1363
  }
1358
1364
  if (!packageJson.name) {
1359
- logger.error('package.json must have a "name" field');
1360
- process.exit(1);
1365
+ return exitWithCommandError('package.json must have a "name" field');
1361
1366
  }
1362
1367
  const packageName = packageJson.name;
1363
1368
  const nameMatches = packageName === expectedName || packageName === `@agentforge/${expectedName}` || packageName.endsWith(`/${expectedName}`);