@agentforge/cli 0.16.2 → 0.16.4

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.cjs CHANGED
@@ -86,6 +86,30 @@ var Logger = class {
86
86
  }
87
87
  };
88
88
  var logger = new Logger();
89
+
90
+ // src/utils/command-errors.ts
91
+ function getErrorMessage(error) {
92
+ if (error instanceof Error) {
93
+ return error.message;
94
+ }
95
+ if (typeof error === "string") {
96
+ return error;
97
+ }
98
+ if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
99
+ return error.message;
100
+ }
101
+ return String(error);
102
+ }
103
+ function exitWithCommandError(error, options = {}) {
104
+ if (options.spinnerFailureText) {
105
+ logger.failSpinner(options.spinnerFailureText);
106
+ }
107
+ if (options.logError !== false) {
108
+ const message = options.message ?? getErrorMessage(error);
109
+ logger.error(options.prefix ? `${options.prefix}: ${message}` : message);
110
+ }
111
+ process.exit(1);
112
+ }
89
113
  async function promptProjectSetup(defaults = {}) {
90
114
  return inquirer__default.default.prompt([
91
115
  {
@@ -445,13 +469,11 @@ async function createCommand(projectName, options) {
445
469
  try {
446
470
  logger.header("\u{1F680} Create AgentForge Project");
447
471
  if (!projectName) {
448
- logger.error("Project name is required");
449
- process.exit(1);
472
+ return exitWithCommandError("Project name is required");
450
473
  }
451
474
  const targetPath = path12__default.default.join(process.cwd(), projectName);
452
475
  if (!await isEmptyDir(targetPath)) {
453
- logger.error(`Directory ${projectName} already exists and is not empty`);
454
- process.exit(1);
476
+ return exitWithCommandError(`Directory ${projectName} already exists and is not empty`);
455
477
  }
456
478
  const answers = await promptProjectSetup({
457
479
  projectName,
@@ -494,7 +516,7 @@ async function createCommand(projectName, options) {
494
516
  try {
495
517
  await installDependencies(targetPath, answers.packageManager);
496
518
  logger.succeedSpinner("Dependencies installed");
497
- } catch (error) {
519
+ } catch {
498
520
  logger.failSpinner("Failed to install dependencies");
499
521
  logger.warn("You can install them manually later");
500
522
  }
@@ -505,7 +527,7 @@ async function createCommand(projectName, options) {
505
527
  await initGitRepository(targetPath);
506
528
  await createInitialCommit(targetPath);
507
529
  logger.succeedSpinner("Git repository initialized");
508
- } catch (error) {
530
+ } catch {
509
531
  logger.failSpinner("Failed to initialize git");
510
532
  logger.warn("You can initialize it manually later");
511
533
  }
@@ -521,8 +543,7 @@ async function createCommand(projectName, options) {
521
543
  logger.newLine();
522
544
  logger.info("Happy coding! \u{1F389}");
523
545
  } catch (error) {
524
- logger.error(`Failed to create project: ${error.message}`);
525
- process.exit(1);
546
+ return exitWithCommandError(error, { prefix: "Failed to create project" });
526
547
  }
527
548
  }
528
549
 
@@ -542,9 +563,9 @@ async function devCommand(options) {
542
563
  await runScript(cwd, "dev", packageManager);
543
564
  logger.succeedSpinner("Development server started");
544
565
  } catch (error) {
545
- logger.failSpinner("Failed to start development server");
546
- logger.error(error.message);
547
- process.exit(1);
566
+ return exitWithCommandError(error, {
567
+ spinnerFailureText: "Failed to start development server"
568
+ });
548
569
  }
549
570
  }
550
571
 
@@ -570,9 +591,7 @@ async function buildCommand(options) {
570
591
  logger.newLine();
571
592
  logger.success("\u2728 Production build ready!");
572
593
  } catch (error) {
573
- logger.failSpinner("Build failed");
574
- logger.error(error.message);
575
- process.exit(1);
594
+ return exitWithCommandError(error, { spinnerFailureText: "Build failed" });
576
595
  }
577
596
  }
578
597
 
@@ -598,9 +617,7 @@ async function testCommand(options) {
598
617
  await runScript(cwd, script, packageManager);
599
618
  logger.succeedSpinner("Tests completed");
600
619
  } catch (error) {
601
- logger.failSpinner("Tests failed");
602
- logger.error(error.message);
603
- process.exit(1);
620
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
604
621
  }
605
622
  }
606
623
 
@@ -617,7 +634,7 @@ async function lintCommand(options) {
617
634
  try {
618
635
  await runScript(cwd, options.fix ? "lint:fix" : "lint", packageManager);
619
636
  logger.succeedSpinner("Linting completed");
620
- } catch (error) {
637
+ } catch {
621
638
  logger.failSpinner("Linting found issues");
622
639
  if (!options.fix) {
623
640
  logger.info("Run with --fix to automatically fix issues");
@@ -628,15 +645,14 @@ async function lintCommand(options) {
628
645
  try {
629
646
  await runScript(cwd, "format", packageManager);
630
647
  logger.succeedSpinner("Formatting completed");
631
- } catch (error) {
648
+ } catch {
632
649
  logger.failSpinner("Formatting failed");
633
650
  }
634
651
  }
635
652
  logger.newLine();
636
653
  logger.success("\u2728 Code quality check completed!");
637
654
  } catch (error) {
638
- logger.error(error.message);
639
- process.exit(1);
655
+ return exitWithCommandError(error);
640
656
  }
641
657
  }
642
658
  async function agentCreateCommand(name, options) {
@@ -677,8 +693,7 @@ async function agentCreateCommand(name, options) {
677
693
  answers.generateTests ? `Run ${chalk4__default.default.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
678
694
  ].filter(Boolean));
679
695
  } catch (error) {
680
- logger.error(`Failed to create agent: ${error.message}`);
681
- process.exit(1);
696
+ return exitWithCommandError(error, { prefix: "Failed to create agent" });
682
697
  }
683
698
  }
684
699
  function generateAgentContent(name, pattern, description) {
@@ -861,8 +876,7 @@ async function agentCreateReusableCommand(name, options) {
861
876
  logger.newLine();
862
877
  logger.info(chalk4__default.default.gray("\u{1F4A1} Tip: See examples/vertical-agents/ for reference implementations"));
863
878
  } catch (error) {
864
- logger.error(`Failed to create reusable agent: ${error.message}`);
865
- process.exit(1);
879
+ return exitWithCommandError(error, { prefix: "Failed to create reusable agent" });
866
880
  }
867
881
  }
868
882
  function kebabToPascal(str) {
@@ -910,8 +924,7 @@ async function agentListCommand(options) {
910
924
  logger.info(`Use ${chalk4__default.default.cyan("--verbose")} for more details`);
911
925
  }
912
926
  } catch (error) {
913
- logger.error(`Failed to list agents: ${error.message}`);
914
- process.exit(1);
927
+ return exitWithCommandError(error, { prefix: "Failed to list agents" });
915
928
  }
916
929
  }
917
930
  function extractPattern(content) {
@@ -935,7 +948,7 @@ async function agentTestCommand(name, options) {
935
948
  if (!await pathExists(testFile)) {
936
949
  logger.error(`Test file not found: ${testFile}`);
937
950
  logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge agent:create ${name} --test`)}`);
938
- process.exit(1);
951
+ return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
939
952
  }
940
953
  logger.info(`Testing agent: ${chalk4__default.default.cyan(name)}`);
941
954
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
@@ -947,9 +960,7 @@ async function agentTestCommand(name, options) {
947
960
  await runScript(cwd, testCommand2, packageManager);
948
961
  logger.succeedSpinner("Tests completed");
949
962
  } catch (error) {
950
- logger.failSpinner("Tests failed");
951
- logger.error(error.message);
952
- process.exit(1);
963
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
953
964
  }
954
965
  }
955
966
  async function agentDeployCommand(name, options) {
@@ -983,10 +994,11 @@ async function agentDeployCommand(name, options) {
983
994
  logger.newLine();
984
995
  logger.info(chalk4__default.default.dim("For detailed deployment guides, see:"));
985
996
  logger.info(chalk4__default.default.dim("https://tvscoundrel.github.io/agentforge/guide/advanced/deployment"));
986
- process.exit(1);
997
+ return exitWithCommandError("Automated agent deployment is not yet implemented", {
998
+ logError: false
999
+ });
987
1000
  } catch (error) {
988
- logger.error(error.message);
989
- process.exit(1);
1001
+ return exitWithCommandError(error);
990
1002
  }
991
1003
  }
992
1004
  async function toolCreateCommand(name, options) {
@@ -1027,8 +1039,7 @@ async function toolCreateCommand(name, options) {
1027
1039
  ];
1028
1040
  logger.list(nextSteps.filter(Boolean));
1029
1041
  } catch (error) {
1030
- logger.error(`Failed to create tool: ${error.message}`);
1031
- process.exit(1);
1042
+ return exitWithCommandError(error, { prefix: "Failed to create tool" });
1032
1043
  }
1033
1044
  }
1034
1045
  function generateToolContent(name, category, description) {
@@ -1176,8 +1187,7 @@ async function toolListCommand(options) {
1176
1187
  logger.info(`Use ${chalk4__default.default.cyan("--verbose")} for more details`);
1177
1188
  }
1178
1189
  } catch (error) {
1179
- logger.error(`Failed to list tools: ${error.message}`);
1180
- process.exit(1);
1190
+ return exitWithCommandError(error, { prefix: "Failed to list tools" });
1181
1191
  }
1182
1192
  }
1183
1193
  function extractCategory(content) {
@@ -1196,7 +1206,7 @@ async function toolTestCommand(name, options) {
1196
1206
  if (!await pathExists(testFile)) {
1197
1207
  logger.error(`Test file not found: ${testFile}`);
1198
1208
  logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge tool:create ${name} --test`)}`);
1199
- process.exit(1);
1209
+ return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
1200
1210
  }
1201
1211
  logger.info(`Testing tool: ${chalk4__default.default.cyan(name)}`);
1202
1212
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
@@ -1208,9 +1218,7 @@ async function toolTestCommand(name, options) {
1208
1218
  await runScript(cwd, testCommand2, packageManager);
1209
1219
  logger.succeedSpinner("Tests completed");
1210
1220
  } catch (error) {
1211
- logger.failSpinner("Tests failed");
1212
- logger.error(error.message);
1213
- process.exit(1);
1221
+ return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
1214
1222
  }
1215
1223
  }
1216
1224
  async function toolPublishCommand(name, options) {
@@ -1232,9 +1240,10 @@ async function toolPublishCommand(name, options) {
1232
1240
  await runScript(toolPath, "test", packageManager);
1233
1241
  logger.succeedSpinner("Tests passed");
1234
1242
  } catch (error) {
1235
- logger.failSpinner("Tests failed");
1236
- logger.error("Cannot publish tool with failing tests");
1237
- process.exit(1);
1243
+ return exitWithCommandError(error, {
1244
+ spinnerFailureText: "Tests failed",
1245
+ message: "Cannot publish tool with failing tests"
1246
+ });
1238
1247
  }
1239
1248
  } else {
1240
1249
  logger.info("\u26A0\uFE0F Skipping tests (no test script found)");
@@ -1245,8 +1254,7 @@ async function toolPublishCommand(name, options) {
1245
1254
  await runScript(toolPath, "build", packageManager);
1246
1255
  logger.succeedSpinner("Build completed");
1247
1256
  } catch (error) {
1248
- logger.failSpinner("Build failed");
1249
- process.exit(1);
1257
+ return exitWithCommandError(error, { spinnerFailureText: "Build failed" });
1250
1258
  }
1251
1259
  } else {
1252
1260
  logger.info("\u26A0\uFE0F Skipping build (no build script found)");
@@ -1264,20 +1272,23 @@ async function toolPublishCommand(name, options) {
1264
1272
  logger.succeedSpinner("Published to npm");
1265
1273
  }
1266
1274
  } catch (error) {
1275
+ const errorMessage = getErrorMessage(error);
1267
1276
  logger.failSpinner("Publishing failed");
1268
- if (error.message.includes("ENEEDAUTH") || error.message.includes("E401")) {
1277
+ if (errorMessage.includes("ENEEDAUTH") || errorMessage.includes("E401")) {
1269
1278
  logger.error("Not authenticated with npm");
1270
1279
  logger.info("Run: npm login");
1271
- } else if (error.message.includes("E403")) {
1280
+ } else if (errorMessage.includes("E403")) {
1272
1281
  logger.error("Permission denied - you may not have access to publish this package");
1273
1282
  logger.info("Check package name and npm organization permissions");
1274
- } else if (error.message.includes("EPUBLISHCONFLICT") || error.message.includes("E409")) {
1283
+ } else if (errorMessage.includes("EPUBLISHCONFLICT") || errorMessage.includes("E409")) {
1275
1284
  logger.error("Version already published");
1276
1285
  logger.info("Update the version in package.json before publishing");
1277
1286
  } else {
1278
- logger.error(error.message);
1287
+ logger.error(errorMessage);
1279
1288
  }
1280
- process.exit(1);
1289
+ return exitWithCommandError(error, {
1290
+ logError: false
1291
+ });
1281
1292
  }
1282
1293
  logger.newLine();
1283
1294
  if (options.dryRun) {
@@ -1291,9 +1302,7 @@ async function toolPublishCommand(name, options) {
1291
1302
  logger.info("Users can now install with: npm install " + name);
1292
1303
  }
1293
1304
  } catch (error) {
1294
- logger.failSpinner("Publishing failed");
1295
- logger.error(error.message);
1296
- process.exit(1);
1305
+ return exitWithCommandError(error, { spinnerFailureText: "Publishing failed" });
1297
1306
  }
1298
1307
  }
1299
1308
  async function resolveToolPath(name) {
@@ -1346,29 +1355,25 @@ async function resolveToolPath(name) {
1346
1355
  "Providing a path to the tool package directory",
1347
1356
  "Have the tool in a standard location (./tools/<name>, ./packages/<name>)"
1348
1357
  ]);
1349
- process.exit(1);
1358
+ return exitWithCommandError(`Could not find tool package: ${name}`, { logError: false });
1350
1359
  }
1351
1360
  async function validateToolPath(toolPath, expectedName) {
1352
1361
  if (!await fs__default.default.pathExists(toolPath)) {
1353
- logger.error(`Tool directory not found: ${toolPath}`);
1354
- process.exit(1);
1362
+ return exitWithCommandError(`Tool directory not found: ${toolPath}`);
1355
1363
  }
1356
1364
  const packageJsonPath = path12__default.default.join(toolPath, "package.json");
1357
1365
  if (!await fs__default.default.pathExists(packageJsonPath)) {
1358
- logger.error(`package.json not found in: ${toolPath}`);
1359
1366
  logger.info("Tool packages must have a package.json file");
1360
- process.exit(1);
1367
+ return exitWithCommandError(`package.json not found in: ${toolPath}`);
1361
1368
  }
1362
1369
  let packageJson;
1363
1370
  try {
1364
1371
  packageJson = await fs__default.default.readJson(packageJsonPath);
1365
1372
  } catch (error) {
1366
- logger.error(`Failed to read package.json: ${error.message}`);
1367
- process.exit(1);
1373
+ return exitWithCommandError(error, { prefix: "Failed to read package.json" });
1368
1374
  }
1369
1375
  if (!packageJson.name) {
1370
- logger.error('package.json must have a "name" field');
1371
- process.exit(1);
1376
+ return exitWithCommandError('package.json must have a "name" field');
1372
1377
  }
1373
1378
  const packageName = packageJson.name;
1374
1379
  const nameMatches = packageName === expectedName || packageName === `@agentforge/${expectedName}` || packageName.endsWith(`/${expectedName}`);