@agentforge/cli 0.3.9 → 0.4.1

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
@@ -1,5 +1,5 @@
1
1
  import { Command } from 'commander';
2
- import chalk from 'chalk';
2
+ import chalk7 from 'chalk';
3
3
  import path from 'path';
4
4
  import ora from 'ora';
5
5
  import inquirer from 'inquirer';
@@ -12,20 +12,20 @@ import { execa } from 'execa';
12
12
  var Logger = class {
13
13
  spinner = null;
14
14
  info(message) {
15
- console.log(chalk.blue("\u2139"), message);
15
+ console.log(chalk7.blue("\u2139"), message);
16
16
  }
17
17
  success(message) {
18
- console.log(chalk.green("\u2714"), message);
18
+ console.log(chalk7.green("\u2714"), message);
19
19
  }
20
20
  warn(message) {
21
- console.log(chalk.yellow("\u26A0"), message);
21
+ console.log(chalk7.yellow("\u26A0"), message);
22
22
  }
23
23
  error(message) {
24
- console.log(chalk.red("\u2716"), message);
24
+ console.log(chalk7.red("\u2716"), message);
25
25
  }
26
26
  debug(message) {
27
27
  if (process.env.DEBUG) {
28
- console.log(chalk.gray("\u{1F41B}"), message);
28
+ console.log(chalk7.gray("\u{1F41B}"), message);
29
29
  }
30
30
  }
31
31
  startSpinner(message) {
@@ -58,19 +58,19 @@ var Logger = class {
58
58
  console.log();
59
59
  }
60
60
  divider() {
61
- console.log(chalk.gray("\u2500".repeat(50)));
61
+ console.log(chalk7.gray("\u2500".repeat(50)));
62
62
  }
63
63
  header(message) {
64
64
  this.newLine();
65
- console.log(chalk.bold.cyan(message));
65
+ console.log(chalk7.bold.cyan(message));
66
66
  this.divider();
67
67
  }
68
68
  code(code) {
69
- console.log(chalk.gray(" " + code));
69
+ console.log(chalk7.gray(" " + code));
70
70
  }
71
71
  list(items) {
72
72
  items.forEach((item) => {
73
- console.log(chalk.gray(" \u2022"), item);
73
+ console.log(chalk7.gray(" \u2022"), item);
74
74
  });
75
75
  }
76
76
  };
@@ -177,12 +177,13 @@ async function promptAgentSetup(defaults = {}) {
177
177
  ]);
178
178
  }
179
179
  async function promptToolSetup(defaults = {}) {
180
- return inquirer.prompt([
180
+ const answers = await inquirer.prompt([
181
181
  {
182
182
  type: "input",
183
183
  name: "name",
184
184
  message: "Tool name:",
185
185
  default: defaults.name,
186
+ when: () => !defaults.name,
186
187
  validate: (input) => {
187
188
  if (!input) return "Tool name is required";
188
189
  if (!/^[a-zA-Z][a-zA-Z0-9]*$/.test(input)) {
@@ -201,25 +202,52 @@ async function promptToolSetup(defaults = {}) {
201
202
  { name: "File - File operations", value: "file" },
202
203
  { name: "Utility - General utilities", value: "utility" }
203
204
  ],
204
- default: defaults.category || "utility"
205
+ default: defaults.category || "utility",
206
+ when: () => !defaults.category
205
207
  },
206
208
  {
207
209
  type: "input",
208
210
  name: "description",
209
211
  message: "Tool description:",
210
212
  default: defaults.description,
213
+ when: () => !defaults.description,
211
214
  validate: (input) => {
212
215
  if (!input) return "Tool description is required";
213
216
  return true;
214
217
  }
215
218
  },
219
+ {
220
+ type: "list",
221
+ name: "structure",
222
+ message: "Tool structure:",
223
+ choices: [
224
+ {
225
+ name: "Single file - Simple tools (<150 lines, single responsibility)",
226
+ value: "single"
227
+ },
228
+ {
229
+ name: "Multi-file - Complex tools (multiple providers, >150 lines)",
230
+ value: "multi"
231
+ }
232
+ ],
233
+ default: defaults.structure || "single",
234
+ when: () => !defaults.structure
235
+ },
216
236
  {
217
237
  type: "confirm",
218
238
  name: "generateTests",
219
239
  message: "Generate tests?",
220
- default: defaults.generateTests !== false
240
+ default: defaults.generateTests !== false,
241
+ when: () => defaults.generateTests === void 0
221
242
  }
222
243
  ]);
244
+ return {
245
+ name: defaults.name || answers.name,
246
+ category: defaults.category || answers.category,
247
+ description: defaults.description || answers.description,
248
+ structure: defaults.structure || answers.structure,
249
+ generateTests: defaults.generateTests !== void 0 ? defaults.generateTests : answers.generateTests
250
+ };
223
251
  }
224
252
  var __filename$1 = fileURLToPath(import.meta.url);
225
253
  var __dirname$1 = path.dirname(__filename$1);
@@ -411,9 +439,9 @@ async function createCommand(projectName, options) {
411
439
  initGit: options.git
412
440
  });
413
441
  logger.newLine();
414
- logger.info(`Creating project: ${chalk.cyan(answers.projectName)}`);
415
- logger.info(`Template: ${chalk.cyan(answers.template)}`);
416
- logger.info(`Package manager: ${chalk.cyan(answers.packageManager)}`);
442
+ logger.info(`Creating project: ${chalk7.cyan(answers.projectName)}`);
443
+ logger.info(`Template: ${chalk7.cyan(answers.template)}`);
444
+ logger.info(`Package manager: ${chalk7.cyan(answers.packageManager)}`);
417
445
  logger.newLine();
418
446
  logger.startSpinner("Creating project directory...");
419
447
  await ensureDir(targetPath);
@@ -461,7 +489,7 @@ async function createCommand(projectName, options) {
461
489
  }
462
490
  }
463
491
  logger.newLine();
464
- logger.success(chalk.bold.green("\u2728 Project created successfully!"));
492
+ logger.success(chalk7.bold.green("\u2728 Project created successfully!"));
465
493
  logger.newLine();
466
494
  logger.header("\u{1F4DD} Next Steps");
467
495
  logger.list([
@@ -598,8 +626,8 @@ async function agentCreateCommand(name, options) {
598
626
  generateTests: options.test
599
627
  });
600
628
  logger.newLine();
601
- logger.info(`Creating agent: ${chalk.cyan(answers.name)}`);
602
- logger.info(`Pattern: ${chalk.cyan(answers.pattern)}`);
629
+ logger.info(`Creating agent: ${chalk7.cyan(answers.name)}`);
630
+ logger.info(`Pattern: ${chalk7.cyan(answers.pattern)}`);
603
631
  logger.newLine();
604
632
  const cwd = process.cwd();
605
633
  const agentDir = path.join(cwd, "src", "agents");
@@ -619,12 +647,12 @@ async function agentCreateCommand(name, options) {
619
647
  logger.succeedSpinner("Test file created");
620
648
  }
621
649
  logger.newLine();
622
- logger.success(chalk.bold.green("\u2728 Agent created successfully!"));
650
+ logger.success(chalk7.bold.green("\u2728 Agent created successfully!"));
623
651
  logger.newLine();
624
652
  logger.header("\u{1F4DD} Next Steps");
625
653
  logger.list([
626
- `Edit ${chalk.cyan(`src/agents/${answers.name}.ts`)} to customize your agent`,
627
- answers.generateTests ? `Run ${chalk.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
654
+ `Edit ${chalk7.cyan(`src/agents/${answers.name}.ts`)} to customize your agent`,
655
+ answers.generateTests ? `Run ${chalk7.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
628
656
  ].filter(Boolean));
629
657
  } catch (error) {
630
658
  logger.error(`Failed to create agent: ${error.message}`);
@@ -744,10 +772,10 @@ async function agentListCommand(options) {
744
772
  const agentFiles = await findFiles("*.ts", agentDir);
745
773
  if (agentFiles.length === 0) {
746
774
  logger.warn("No agents found");
747
- logger.info(`Create an agent with: ${chalk.cyan("agentforge agent:create <name>")}`);
775
+ logger.info(`Create an agent with: ${chalk7.cyan("agentforge agent:create <name>")}`);
748
776
  return;
749
777
  }
750
- logger.info(`Found ${chalk.cyan(agentFiles.length)} agent(s):
778
+ logger.info(`Found ${chalk7.cyan(agentFiles.length)} agent(s):
751
779
  `);
752
780
  for (const file of agentFiles) {
753
781
  const agentName = path.basename(file, ".ts");
@@ -756,22 +784,22 @@ async function agentListCommand(options) {
756
784
  const content = await readFile(agentPath);
757
785
  const pattern = extractPattern(content);
758
786
  const description = extractDescription(content);
759
- logger.info(chalk.bold.cyan(` ${agentName}`));
787
+ logger.info(chalk7.bold.cyan(` ${agentName}`));
760
788
  if (pattern) {
761
789
  logger.info(` Pattern: ${pattern}`);
762
790
  }
763
791
  if (description) {
764
792
  logger.info(` Description: ${description}`);
765
793
  }
766
- logger.info(` Path: ${chalk.gray(agentPath)}`);
794
+ logger.info(` Path: ${chalk7.gray(agentPath)}`);
767
795
  logger.newLine();
768
796
  } else {
769
- logger.info(` \u2022 ${chalk.cyan(agentName)}`);
797
+ logger.info(` \u2022 ${chalk7.cyan(agentName)}`);
770
798
  }
771
799
  }
772
800
  if (!options.verbose) {
773
801
  logger.newLine();
774
- logger.info(`Use ${chalk.cyan("--verbose")} for more details`);
802
+ logger.info(`Use ${chalk7.cyan("--verbose")} for more details`);
775
803
  }
776
804
  } catch (error) {
777
805
  logger.error(`Failed to list agents: ${error.message}`);
@@ -798,10 +826,10 @@ async function agentTestCommand(name, options) {
798
826
  const testFile = path.join(cwd, "tests", "agents", `${name}.test.ts`);
799
827
  if (!await pathExists(testFile)) {
800
828
  logger.error(`Test file not found: ${testFile}`);
801
- logger.info(`Create tests with: ${chalk.cyan(`agentforge agent:create ${name} --test`)}`);
829
+ logger.info(`Create tests with: ${chalk7.cyan(`agentforge agent:create ${name} --test`)}`);
802
830
  process.exit(1);
803
831
  }
804
- logger.info(`Testing agent: ${chalk.cyan(name)}`);
832
+ logger.info(`Testing agent: ${chalk7.cyan(name)}`);
805
833
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
806
834
  logger.newLine();
807
835
  const packageManager = await detectPackageManager(cwd);
@@ -819,8 +847,8 @@ async function agentTestCommand(name, options) {
819
847
  async function agentDeployCommand(name, options) {
820
848
  try {
821
849
  logger.header("\u{1F680} Deploy Agent");
822
- logger.info(`Agent: ${chalk.cyan(name)}`);
823
- logger.info(`Environment: ${chalk.cyan(options.environment || "production")}`);
850
+ logger.info(`Agent: ${chalk7.cyan(name)}`);
851
+ logger.info(`Environment: ${chalk7.cyan(options.environment || "production")}`);
824
852
  logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
825
853
  logger.newLine();
826
854
  if (options.dryRun) {
@@ -836,7 +864,7 @@ async function agentDeployCommand(name, options) {
836
864
  logger.succeedSpinner("Agent deployed successfully");
837
865
  }
838
866
  logger.newLine();
839
- logger.success(chalk.bold.green("\u2728 Deployment completed!"));
867
+ logger.success(chalk7.bold.green("\u2728 Deployment completed!"));
840
868
  logger.newLine();
841
869
  logger.info("Note: Actual deployment implementation coming soon");
842
870
  logger.info("For now, please use the deployment templates in the templates/deployment directory");
@@ -852,38 +880,37 @@ async function toolCreateCommand(name, options) {
852
880
  const answers = await promptToolSetup({
853
881
  name,
854
882
  category: options.category,
883
+ structure: options.structure,
884
+ description: options.description,
855
885
  generateTests: options.test
856
886
  });
857
887
  logger.newLine();
858
- logger.info(`Creating tool: ${chalk.cyan(answers.name)}`);
859
- logger.info(`Category: ${chalk.cyan(answers.category)}`);
888
+ logger.info(`Creating tool: ${chalk7.cyan(answers.name)}`);
889
+ logger.info(`Category: ${chalk7.cyan(answers.category)}`);
890
+ logger.info(`Structure: ${chalk7.cyan(answers.structure)}`);
860
891
  logger.newLine();
861
892
  const cwd = process.cwd();
862
- const toolDir = path.join(cwd, "src", "tools");
863
- const toolFile = path.join(toolDir, `${answers.name}.ts`);
864
- logger.startSpinner("Creating tool file...");
865
- await ensureDir(toolDir);
866
- const toolContent = generateToolContent(answers.name, answers.category, answers.description);
867
- await writeFile(toolFile, toolContent);
868
- logger.succeedSpinner("Tool file created");
869
- if (answers.generateTests) {
870
- logger.startSpinner("Creating test file...");
871
- const testDir = path.join(cwd, "tests", "tools");
872
- const testFile = path.join(testDir, `${answers.name}.test.ts`);
873
- await ensureDir(testDir);
874
- const testContent = generateTestContent2(answers.name);
875
- await writeFile(testFile, testContent);
876
- logger.succeedSpinner("Test file created");
893
+ if (answers.structure === "multi") {
894
+ await createMultiFileTool(cwd, answers);
895
+ } else {
896
+ await createSingleFileTool(cwd, answers);
877
897
  }
878
898
  logger.newLine();
879
- logger.success(chalk.bold.green("\u2728 Tool created successfully!"));
899
+ logger.success(chalk7.bold.green("\u2728 Tool created successfully!"));
880
900
  logger.newLine();
881
901
  logger.header("\u{1F4DD} Next Steps");
882
- logger.list([
883
- `Edit ${chalk.cyan(`src/tools/${answers.name}.ts`)} to implement your tool`,
884
- answers.generateTests ? `Run ${chalk.cyan(`pnpm test tests/tools/${answers.name}.test.ts`)} to test your tool` : "",
902
+ const nextSteps = answers.structure === "multi" ? [
903
+ `Edit ${chalk7.cyan(`src/tools/${answers.name}/index.ts`)} to implement your tool`,
904
+ `Add providers in ${chalk7.cyan(`src/tools/${answers.name}/providers/`)}`,
905
+ `Define types in ${chalk7.cyan(`src/tools/${answers.name}/types.ts`)}`,
906
+ answers.generateTests ? `Run ${chalk7.cyan(`pnpm test ${answers.name}`)} to test your tool` : "",
885
907
  `Register the tool in your agent's tool registry`
886
- ].filter(Boolean));
908
+ ] : [
909
+ `Edit ${chalk7.cyan(`src/tools/${answers.name}.ts`)} to implement your tool`,
910
+ answers.generateTests ? `Run ${chalk7.cyan(`pnpm test tests/tools/${answers.name}.test.ts`)} to test your tool` : "",
911
+ `Register the tool in your agent's tool registry`
912
+ ];
913
+ logger.list(nextSteps.filter(Boolean));
887
914
  } catch (error) {
888
915
  logger.error(`Failed to create tool: ${error.message}`);
889
916
  process.exit(1);
@@ -939,6 +966,46 @@ describe('${capitalize2(name)} Tool', () => {
939
966
  function capitalize2(str) {
940
967
  return str.charAt(0).toUpperCase() + str.slice(1);
941
968
  }
969
+ async function createSingleFileTool(cwd, answers) {
970
+ const toolDir = path.join(cwd, "src", "tools");
971
+ const toolFile = path.join(toolDir, `${answers.name}.ts`);
972
+ logger.startSpinner("Creating tool file...");
973
+ await ensureDir(toolDir);
974
+ const toolContent = generateToolContent(answers.name, answers.category, answers.description);
975
+ await writeFile(toolFile, toolContent);
976
+ logger.succeedSpinner("Tool file created");
977
+ if (answers.generateTests) {
978
+ logger.startSpinner("Creating test file...");
979
+ const testDir = path.join(cwd, "tests", "tools");
980
+ const testFile = path.join(testDir, `${answers.name}.test.ts`);
981
+ await ensureDir(testDir);
982
+ const testContent = generateTestContent2(answers.name);
983
+ await writeFile(testFile, testContent);
984
+ logger.succeedSpinner("Test file created");
985
+ }
986
+ }
987
+ async function createMultiFileTool(cwd, answers) {
988
+ const toolDir = path.join(cwd, "src", "tools", answers.name);
989
+ logger.startSpinner("Creating tool directory structure...");
990
+ await ensureDir(toolDir);
991
+ const templatePath = getTemplatePath("tool-multi");
992
+ const replacements = {
993
+ TOOL_NAME: answers.name,
994
+ TOOL_NAME_PASCAL: capitalize2(answers.name),
995
+ TOOL_NAME_CAMEL: answers.name.charAt(0).toLowerCase() + answers.name.slice(1),
996
+ TOOL_DESCRIPTION: answers.description,
997
+ TOOL_CATEGORY: answers.category
998
+ };
999
+ await copyTemplate(templatePath, toolDir, replacements);
1000
+ logger.succeedSpinner("Tool directory structure created");
1001
+ if (!answers.generateTests) {
1002
+ logger.startSpinner("Cleaning up test files...");
1003
+ const fs4 = await import('fs-extra');
1004
+ const testDir = path.join(toolDir, "__tests__");
1005
+ await fs4.remove(testDir);
1006
+ logger.succeedSpinner("Test files removed");
1007
+ }
1008
+ }
942
1009
  async function toolListCommand(options) {
943
1010
  try {
944
1011
  logger.header("\u{1F4CB} List Tools");
@@ -947,7 +1014,7 @@ async function toolListCommand(options) {
947
1014
  const toolFiles = await findFiles("*.ts", toolDir);
948
1015
  if (toolFiles.length === 0) {
949
1016
  logger.warn("No tools found");
950
- logger.info(`Create a tool with: ${chalk.cyan("agentforge tool:create <name>")}`);
1017
+ logger.info(`Create a tool with: ${chalk7.cyan("agentforge tool:create <name>")}`);
951
1018
  return;
952
1019
  }
953
1020
  let filteredTools = toolFiles;
@@ -966,7 +1033,7 @@ async function toolListCommand(options) {
966
1033
  logger.warn(`No tools found in category: ${options.category}`);
967
1034
  return;
968
1035
  }
969
- logger.info(`Found ${chalk.cyan(filteredTools.length)} tool(s):
1036
+ logger.info(`Found ${chalk7.cyan(filteredTools.length)} tool(s):
970
1037
  `);
971
1038
  for (const file of filteredTools) {
972
1039
  const toolName = path.basename(file, ".ts");
@@ -975,22 +1042,22 @@ async function toolListCommand(options) {
975
1042
  const content = await readFile(toolPath);
976
1043
  const category = extractCategory(content);
977
1044
  const description = extractDescription2(content);
978
- logger.info(chalk.bold.cyan(` ${toolName}`));
1045
+ logger.info(chalk7.bold.cyan(` ${toolName}`));
979
1046
  if (category) {
980
1047
  logger.info(` Category: ${category}`);
981
1048
  }
982
1049
  if (description) {
983
1050
  logger.info(` Description: ${description}`);
984
1051
  }
985
- logger.info(` Path: ${chalk.gray(toolPath)}`);
1052
+ logger.info(` Path: ${chalk7.gray(toolPath)}`);
986
1053
  logger.newLine();
987
1054
  } else {
988
- logger.info(` \u2022 ${chalk.cyan(toolName)}`);
1055
+ logger.info(` \u2022 ${chalk7.cyan(toolName)}`);
989
1056
  }
990
1057
  }
991
1058
  if (!options.verbose) {
992
1059
  logger.newLine();
993
- logger.info(`Use ${chalk.cyan("--verbose")} for more details`);
1060
+ logger.info(`Use ${chalk7.cyan("--verbose")} for more details`);
994
1061
  }
995
1062
  } catch (error) {
996
1063
  logger.error(`Failed to list tools: ${error.message}`);
@@ -1012,10 +1079,10 @@ async function toolTestCommand(name, options) {
1012
1079
  const testFile = path.join(cwd, "tests", "tools", `${name}.test.ts`);
1013
1080
  if (!await pathExists(testFile)) {
1014
1081
  logger.error(`Test file not found: ${testFile}`);
1015
- logger.info(`Create tests with: ${chalk.cyan(`agentforge tool:create ${name} --test`)}`);
1082
+ logger.info(`Create tests with: ${chalk7.cyan(`agentforge tool:create ${name} --test`)}`);
1016
1083
  process.exit(1);
1017
1084
  }
1018
- logger.info(`Testing tool: ${chalk.cyan(name)}`);
1085
+ logger.info(`Testing tool: ${chalk7.cyan(name)}`);
1019
1086
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
1020
1087
  logger.newLine();
1021
1088
  const packageManager = await detectPackageManager(cwd);
@@ -1033,8 +1100,8 @@ async function toolTestCommand(name, options) {
1033
1100
  async function toolPublishCommand(name, options) {
1034
1101
  try {
1035
1102
  logger.header("\u{1F4E6} Publish Tool");
1036
- logger.info(`Tool: ${chalk.cyan(name)}`);
1037
- logger.info(`Tag: ${chalk.cyan(options.tag || "latest")}`);
1103
+ logger.info(`Tool: ${chalk7.cyan(name)}`);
1104
+ logger.info(`Tag: ${chalk7.cyan(options.tag || "latest")}`);
1038
1105
  logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
1039
1106
  logger.newLine();
1040
1107
  if (options.dryRun) {
@@ -1066,7 +1133,7 @@ async function toolPublishCommand(name, options) {
1066
1133
  logger.succeedSpinner("Published to npm");
1067
1134
  }
1068
1135
  logger.newLine();
1069
- logger.success(chalk.bold.green("\u2728 Tool published successfully!"));
1136
+ logger.success(chalk7.bold.green("\u2728 Tool published successfully!"));
1070
1137
  logger.newLine();
1071
1138
  logger.info("Note: Actual npm publishing implementation coming soon");
1072
1139
  logger.info("For now, please use npm publish manually");
@@ -1091,7 +1158,7 @@ agent.command("list").description("List all agents").option("-v, --verbose", "Sh
1091
1158
  agent.command("test <name>").description("Test a specific agent").option("-w, --watch", "Watch mode").action(agentTestCommand);
1092
1159
  agent.command("deploy <name>").description("Deploy an agent").option("-e, --environment <env>", "Deployment environment", "production").option("--dry-run", "Dry run without actual deployment").action(agentDeployCommand);
1093
1160
  var tool = program.command("tool").description("Manage tools");
1094
- tool.command("create <name>").description("Create a new tool").option("-c, --category <category>", "Tool category (web, data, file, utility)", "utility").option("--no-test", "Skip test generation").action(toolCreateCommand);
1161
+ tool.command("create <name>").description("Create a new tool").option("-c, --category <category>", "Tool category (web, data, file, utility)", "utility").option("-s, --structure <structure>", "Tool structure (single, multi)", "single").option("-d, --description <description>", "Tool description").option("--no-test", "Skip test generation").action(toolCreateCommand);
1095
1162
  tool.command("list").description("List all tools").option("-c, --category <category>", "Filter by category").option("-v, --verbose", "Show detailed information").action(toolListCommand);
1096
1163
  tool.command("test <name>").description("Test a specific tool").option("-w, --watch", "Watch mode").action(toolTestCommand);
1097
1164
  tool.command("publish <name>").description("Publish a tool to npm").option("--tag <tag>", "npm tag", "latest").option("--dry-run", "Dry run without actual publishing").action(toolPublishCommand);
@@ -1101,7 +1168,7 @@ async function run() {
1101
1168
  await program.parseAsync(process.argv);
1102
1169
  } catch (error) {
1103
1170
  if (error.code !== "commander.help" && error.code !== "commander.version") {
1104
- console.error(chalk.red("Error:"), error.message);
1171
+ console.error(chalk7.red("Error:"), error.message);
1105
1172
  process.exit(1);
1106
1173
  }
1107
1174
  }