@agentforge/cli 0.5.1 → 0.5.2

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,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
- import chalk7 from 'chalk';
3
- import path from 'path';
2
+ import chalk4 from 'chalk';
3
+ import path6 from 'path';
4
4
  import ora from 'ora';
5
5
  import inquirer from 'inquirer';
6
6
  import fs from 'fs-extra';
@@ -12,20 +12,20 @@ import { execa } from 'execa';
12
12
  var Logger = class {
13
13
  spinner = null;
14
14
  info(message) {
15
- console.log(chalk7.blue("\u2139"), message);
15
+ console.log(chalk4.blue("\u2139"), message);
16
16
  }
17
17
  success(message) {
18
- console.log(chalk7.green("\u2714"), message);
18
+ console.log(chalk4.green("\u2714"), message);
19
19
  }
20
20
  warn(message) {
21
- console.log(chalk7.yellow("\u26A0"), message);
21
+ console.log(chalk4.yellow("\u26A0"), message);
22
22
  }
23
23
  error(message) {
24
- console.log(chalk7.red("\u2716"), message);
24
+ console.log(chalk4.red("\u2716"), message);
25
25
  }
26
26
  debug(message) {
27
27
  if (process.env.DEBUG) {
28
- console.log(chalk7.gray("\u{1F41B}"), message);
28
+ console.log(chalk4.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(chalk7.gray("\u2500".repeat(50)));
61
+ console.log(chalk4.gray("\u2500".repeat(50)));
62
62
  }
63
63
  header(message) {
64
64
  this.newLine();
65
- console.log(chalk7.bold.cyan(message));
65
+ console.log(chalk4.bold.cyan(message));
66
66
  this.divider();
67
67
  }
68
68
  code(code) {
69
- console.log(chalk7.gray(" " + code));
69
+ console.log(chalk4.gray(" " + code));
70
70
  }
71
71
  list(items) {
72
72
  items.forEach((item) => {
73
- console.log(chalk7.gray(" \u2022"), item);
73
+ console.log(chalk4.gray(" \u2022"), item);
74
74
  });
75
75
  }
76
76
  };
@@ -250,7 +250,7 @@ async function promptToolSetup(defaults = {}) {
250
250
  };
251
251
  }
252
252
  var __filename$1 = fileURLToPath(import.meta.url);
253
- var __dirname$1 = path.dirname(__filename$1);
253
+ var __dirname$1 = path6.dirname(__filename$1);
254
254
  async function ensureDir(dir) {
255
255
  await fs.ensureDir(dir);
256
256
  }
@@ -268,9 +268,9 @@ async function copyTemplate(templatePath, targetPath, replacements = {}) {
268
268
  throw new Error(`No files found in template: ${templatePath}`);
269
269
  }
270
270
  for (const file of files) {
271
- const sourcePath = path.join(templatePath, file);
272
- const destPath = path.join(targetPath, file);
273
- await fs.ensureDir(path.dirname(destPath));
271
+ const sourcePath = path6.join(templatePath, file);
272
+ const destPath = path6.join(targetPath, file);
273
+ await fs.ensureDir(path6.dirname(destPath));
274
274
  let content = await fs.readFile(sourcePath, "utf-8");
275
275
  for (const [key, value] of Object.entries(replacements)) {
276
276
  content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
@@ -294,11 +294,11 @@ async function readFile(filePath) {
294
294
  return fs.readFile(filePath, "utf-8");
295
295
  }
296
296
  async function writeFile(filePath, content) {
297
- await fs.ensureDir(path.dirname(filePath));
297
+ await fs.ensureDir(path6.dirname(filePath));
298
298
  await fs.writeFile(filePath, content);
299
299
  }
300
300
  function getTemplatePath(template) {
301
- return path.join(__dirname$1, "..", "templates", template);
301
+ return path6.join(__dirname$1, "..", "templates", template);
302
302
  }
303
303
  async function isEmptyDir(dir) {
304
304
  if (!await pathExists(dir)) {
@@ -308,13 +308,13 @@ async function isEmptyDir(dir) {
308
308
  return files.length === 0;
309
309
  }
310
310
  async function detectPackageManager(cwd = process.cwd()) {
311
- if (await fs.pathExists(path.join(cwd, "pnpm-lock.yaml"))) {
311
+ if (await fs.pathExists(path6.join(cwd, "pnpm-lock.yaml"))) {
312
312
  return "pnpm";
313
313
  }
314
- if (await fs.pathExists(path.join(cwd, "yarn.lock"))) {
314
+ if (await fs.pathExists(path6.join(cwd, "yarn.lock"))) {
315
315
  return "yarn";
316
316
  }
317
- if (await fs.pathExists(path.join(cwd, "package-lock.json"))) {
317
+ if (await fs.pathExists(path6.join(cwd, "package-lock.json"))) {
318
318
  return "npm";
319
319
  }
320
320
  try {
@@ -411,7 +411,7 @@ pnpm-debug.log*
411
411
  .temp/
412
412
  .tmp/
413
413
  `;
414
- await fs.writeFile(path.join(cwd, ".gitignore"), gitignore);
414
+ await fs.writeFile(path6.join(cwd, ".gitignore"), gitignore);
415
415
  }
416
416
  async function createInitialCommit(cwd) {
417
417
  await execa("git", ["add", "."], { cwd });
@@ -426,7 +426,7 @@ async function createCommand(projectName, options) {
426
426
  logger.error("Project name is required");
427
427
  process.exit(1);
428
428
  }
429
- const targetPath = path.join(process.cwd(), projectName);
429
+ const targetPath = path6.join(process.cwd(), projectName);
430
430
  if (!await isEmptyDir(targetPath)) {
431
431
  logger.error(`Directory ${projectName} already exists and is not empty`);
432
432
  process.exit(1);
@@ -439,9 +439,9 @@ async function createCommand(projectName, options) {
439
439
  initGit: options.git
440
440
  });
441
441
  logger.newLine();
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)}`);
442
+ logger.info(`Creating project: ${chalk4.cyan(answers.projectName)}`);
443
+ logger.info(`Template: ${chalk4.cyan(answers.template)}`);
444
+ logger.info(`Package manager: ${chalk4.cyan(answers.packageManager)}`);
445
445
  logger.newLine();
446
446
  logger.startSpinner("Creating project directory...");
447
447
  await ensureDir(targetPath);
@@ -456,7 +456,7 @@ async function createCommand(projectName, options) {
456
456
  });
457
457
  logger.succeedSpinner("Template files copied");
458
458
  logger.startSpinner("Updating package.json...");
459
- const packageJsonPath = path.join(targetPath, "package.json");
459
+ const packageJsonPath = path6.join(targetPath, "package.json");
460
460
  const packageJson = await readJson(packageJsonPath);
461
461
  packageJson.name = answers.projectName;
462
462
  if (answers.author) {
@@ -489,7 +489,7 @@ async function createCommand(projectName, options) {
489
489
  }
490
490
  }
491
491
  logger.newLine();
492
- logger.success(chalk7.bold.green("\u2728 Project created successfully!"));
492
+ logger.success(chalk4.bold.green("\u2728 Project created successfully!"));
493
493
  logger.newLine();
494
494
  logger.header("\u{1F4DD} Next Steps");
495
495
  logger.list([
@@ -626,12 +626,12 @@ async function agentCreateCommand(name, options) {
626
626
  generateTests: options.test
627
627
  });
628
628
  logger.newLine();
629
- logger.info(`Creating agent: ${chalk7.cyan(answers.name)}`);
630
- logger.info(`Pattern: ${chalk7.cyan(answers.pattern)}`);
629
+ logger.info(`Creating agent: ${chalk4.cyan(answers.name)}`);
630
+ logger.info(`Pattern: ${chalk4.cyan(answers.pattern)}`);
631
631
  logger.newLine();
632
632
  const cwd = process.cwd();
633
- const agentDir = path.join(cwd, "src", "agents");
634
- const agentFile = path.join(agentDir, `${answers.name}.ts`);
633
+ const agentDir = path6.join(cwd, "src", "agents");
634
+ const agentFile = path6.join(agentDir, `${answers.name}.ts`);
635
635
  logger.startSpinner("Creating agent file...");
636
636
  await ensureDir(agentDir);
637
637
  const agentContent = generateAgentContent(answers.name, answers.pattern, answers.description);
@@ -639,20 +639,20 @@ async function agentCreateCommand(name, options) {
639
639
  logger.succeedSpinner("Agent file created");
640
640
  if (answers.generateTests) {
641
641
  logger.startSpinner("Creating test file...");
642
- const testDir = path.join(cwd, "tests", "agents");
643
- const testFile = path.join(testDir, `${answers.name}.test.ts`);
642
+ const testDir = path6.join(cwd, "tests", "agents");
643
+ const testFile = path6.join(testDir, `${answers.name}.test.ts`);
644
644
  await ensureDir(testDir);
645
645
  const testContent = generateTestContent(answers.name, answers.pattern);
646
646
  await writeFile(testFile, testContent);
647
647
  logger.succeedSpinner("Test file created");
648
648
  }
649
649
  logger.newLine();
650
- logger.success(chalk7.bold.green("\u2728 Agent created successfully!"));
650
+ logger.success(chalk4.bold.green("\u2728 Agent created successfully!"));
651
651
  logger.newLine();
652
652
  logger.header("\u{1F4DD} Next Steps");
653
653
  logger.list([
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` : ""
654
+ `Edit ${chalk4.cyan(`src/agents/${answers.name}.ts`)} to customize your agent`,
655
+ answers.generateTests ? `Run ${chalk4.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
656
656
  ].filter(Boolean));
657
657
  } catch (error) {
658
658
  logger.error(`Failed to create agent: ${error.message}`);
@@ -764,42 +764,129 @@ describe('${capitalize(name)} ${pattern === "multi-agent" ? "System" : "Agent"}'
764
764
  function capitalize(str) {
765
765
  return str.charAt(0).toUpperCase() + str.slice(1);
766
766
  }
767
+ async function agentCreateReusableCommand(name, options) {
768
+ try {
769
+ logger.header("\u{1F4E6} Create Reusable Agent");
770
+ const answers = await inquirer.prompt([
771
+ {
772
+ type: "input",
773
+ name: "name",
774
+ message: "Agent name (e.g., customer-support):",
775
+ default: name,
776
+ validate: (input) => {
777
+ if (!input) return "Agent name is required";
778
+ if (!/^[a-z][a-z0-9-]*$/.test(input)) {
779
+ return "Agent name must be lowercase with hyphens (e.g., customer-support)";
780
+ }
781
+ return true;
782
+ }
783
+ },
784
+ {
785
+ type: "input",
786
+ name: "description",
787
+ message: "Agent description:",
788
+ default: options.description || `A reusable ${name} agent`
789
+ },
790
+ {
791
+ type: "input",
792
+ name: "author",
793
+ message: "Author name:",
794
+ default: options.author || ""
795
+ }
796
+ ]);
797
+ logger.newLine();
798
+ logger.info(`Creating reusable agent: ${chalk4.cyan(answers.name)}`);
799
+ logger.info(`Description: ${chalk4.gray(answers.description)}`);
800
+ logger.newLine();
801
+ const cwd = process.cwd();
802
+ const agentDir = path6.join(cwd, answers.name);
803
+ const agentNameKebab = answers.name;
804
+ const agentNamePascal = kebabToPascal(agentNameKebab);
805
+ const agentNameCamel = kebabToCamel(agentNameKebab);
806
+ const packageName = `@agentforge/${agentNameKebab}`;
807
+ const replacements = {
808
+ AGENT_NAME_KEBAB: agentNameKebab,
809
+ AGENT_NAME_PASCAL: agentNamePascal,
810
+ AGENT_NAME_CAMEL: agentNameCamel,
811
+ AGENT_DESCRIPTION: answers.description,
812
+ PACKAGE_NAME: packageName,
813
+ AUTHOR: answers.author || "Your Name"
814
+ };
815
+ logger.startSpinner("Creating agent structure...");
816
+ const templatePath = getTemplatePath("reusable-agent");
817
+ await copyTemplate(templatePath, agentDir, replacements);
818
+ logger.succeedSpinner("Agent structure created");
819
+ logger.startSpinner("Organizing files...");
820
+ const fs4 = await import('fs-extra');
821
+ const srcDir = path6.join(agentDir, "src");
822
+ await fs4.ensureDir(srcDir);
823
+ await fs4.move(path6.join(agentDir, "index.ts"), path6.join(srcDir, "index.ts"));
824
+ await fs4.move(path6.join(agentDir, "prompt-loader.ts"), path6.join(srcDir, "prompt-loader.ts"));
825
+ await fs4.move(path6.join(agentDir, "index.test.ts"), path6.join(srcDir, "index.test.ts"));
826
+ logger.succeedSpinner("Files organized");
827
+ logger.newLine();
828
+ logger.success(chalk4.bold.green("\u2728 Reusable agent created successfully!"));
829
+ logger.newLine();
830
+ logger.header("\u{1F4DD} Next Steps");
831
+ const nextSteps = [
832
+ `cd ${chalk4.cyan(answers.name)}`,
833
+ `Install dependencies: ${chalk4.cyan("pnpm install")}`,
834
+ `Edit ${chalk4.cyan("prompts/system.md")} to customize the agent prompt`,
835
+ `Edit ${chalk4.cyan("src/index.ts")} to add tools and configuration`,
836
+ `Run tests: ${chalk4.cyan("pnpm test")}`,
837
+ `Build: ${chalk4.cyan("pnpm build")}`
838
+ ];
839
+ logger.list(nextSteps);
840
+ logger.newLine();
841
+ logger.info(chalk4.gray("\u{1F4A1} Tip: See examples/reusable-agents/ for reference implementations"));
842
+ } catch (error) {
843
+ logger.error(`Failed to create reusable agent: ${error.message}`);
844
+ process.exit(1);
845
+ }
846
+ }
847
+ function kebabToPascal(str) {
848
+ return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
849
+ }
850
+ function kebabToCamel(str) {
851
+ const pascal = kebabToPascal(str);
852
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
853
+ }
767
854
  async function agentListCommand(options) {
768
855
  try {
769
856
  logger.header("\u{1F4CB} List Agents");
770
857
  const cwd = process.cwd();
771
- const agentDir = path.join(cwd, "src", "agents");
858
+ const agentDir = path6.join(cwd, "src", "agents");
772
859
  const agentFiles = await findFiles("*.ts", agentDir);
773
860
  if (agentFiles.length === 0) {
774
861
  logger.warn("No agents found");
775
- logger.info(`Create an agent with: ${chalk7.cyan("agentforge agent:create <name>")}`);
862
+ logger.info(`Create an agent with: ${chalk4.cyan("agentforge agent:create <name>")}`);
776
863
  return;
777
864
  }
778
- logger.info(`Found ${chalk7.cyan(agentFiles.length)} agent(s):
865
+ logger.info(`Found ${chalk4.cyan(agentFiles.length)} agent(s):
779
866
  `);
780
867
  for (const file of agentFiles) {
781
- const agentName = path.basename(file, ".ts");
782
- const agentPath = path.join(agentDir, file);
868
+ const agentName = path6.basename(file, ".ts");
869
+ const agentPath = path6.join(agentDir, file);
783
870
  if (options.verbose) {
784
871
  const content = await readFile(agentPath);
785
872
  const pattern = extractPattern(content);
786
873
  const description = extractDescription(content);
787
- logger.info(chalk7.bold.cyan(` ${agentName}`));
874
+ logger.info(chalk4.bold.cyan(` ${agentName}`));
788
875
  if (pattern) {
789
876
  logger.info(` Pattern: ${pattern}`);
790
877
  }
791
878
  if (description) {
792
879
  logger.info(` Description: ${description}`);
793
880
  }
794
- logger.info(` Path: ${chalk7.gray(agentPath)}`);
881
+ logger.info(` Path: ${chalk4.gray(agentPath)}`);
795
882
  logger.newLine();
796
883
  } else {
797
- logger.info(` \u2022 ${chalk7.cyan(agentName)}`);
884
+ logger.info(` \u2022 ${chalk4.cyan(agentName)}`);
798
885
  }
799
886
  }
800
887
  if (!options.verbose) {
801
888
  logger.newLine();
802
- logger.info(`Use ${chalk7.cyan("--verbose")} for more details`);
889
+ logger.info(`Use ${chalk4.cyan("--verbose")} for more details`);
803
890
  }
804
891
  } catch (error) {
805
892
  logger.error(`Failed to list agents: ${error.message}`);
@@ -823,13 +910,13 @@ async function agentTestCommand(name, options) {
823
910
  try {
824
911
  logger.header("\u{1F9EA} Test Agent");
825
912
  const cwd = process.cwd();
826
- const testFile = path.join(cwd, "tests", "agents", `${name}.test.ts`);
913
+ const testFile = path6.join(cwd, "tests", "agents", `${name}.test.ts`);
827
914
  if (!await pathExists(testFile)) {
828
915
  logger.error(`Test file not found: ${testFile}`);
829
- logger.info(`Create tests with: ${chalk7.cyan(`agentforge agent:create ${name} --test`)}`);
916
+ logger.info(`Create tests with: ${chalk4.cyan(`agentforge agent:create ${name} --test`)}`);
830
917
  process.exit(1);
831
918
  }
832
- logger.info(`Testing agent: ${chalk7.cyan(name)}`);
919
+ logger.info(`Testing agent: ${chalk4.cyan(name)}`);
833
920
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
834
921
  logger.newLine();
835
922
  const packageManager = await detectPackageManager(cwd);
@@ -847,8 +934,8 @@ async function agentTestCommand(name, options) {
847
934
  async function agentDeployCommand(name, options) {
848
935
  try {
849
936
  logger.header("\u{1F680} Deploy Agent");
850
- logger.info(`Agent: ${chalk7.cyan(name)}`);
851
- logger.info(`Environment: ${chalk7.cyan(options.environment || "production")}`);
937
+ logger.info(`Agent: ${chalk4.cyan(name)}`);
938
+ logger.info(`Environment: ${chalk4.cyan(options.environment || "production")}`);
852
939
  logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
853
940
  logger.newLine();
854
941
  if (options.dryRun) {
@@ -864,7 +951,7 @@ async function agentDeployCommand(name, options) {
864
951
  logger.succeedSpinner("Agent deployed successfully");
865
952
  }
866
953
  logger.newLine();
867
- logger.success(chalk7.bold.green("\u2728 Deployment completed!"));
954
+ logger.success(chalk4.bold.green("\u2728 Deployment completed!"));
868
955
  logger.newLine();
869
956
  logger.info("Note: Actual deployment implementation coming soon");
870
957
  logger.info("For now, please use the deployment templates in the templates/deployment directory");
@@ -885,9 +972,9 @@ async function toolCreateCommand(name, options) {
885
972
  generateTests: options.test
886
973
  });
887
974
  logger.newLine();
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)}`);
975
+ logger.info(`Creating tool: ${chalk4.cyan(answers.name)}`);
976
+ logger.info(`Category: ${chalk4.cyan(answers.category)}`);
977
+ logger.info(`Structure: ${chalk4.cyan(answers.structure)}`);
891
978
  logger.newLine();
892
979
  const cwd = process.cwd();
893
980
  if (answers.structure === "multi") {
@@ -896,18 +983,18 @@ async function toolCreateCommand(name, options) {
896
983
  await createSingleFileTool(cwd, answers);
897
984
  }
898
985
  logger.newLine();
899
- logger.success(chalk7.bold.green("\u2728 Tool created successfully!"));
986
+ logger.success(chalk4.bold.green("\u2728 Tool created successfully!"));
900
987
  logger.newLine();
901
988
  logger.header("\u{1F4DD} Next Steps");
902
989
  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` : "",
990
+ `Edit ${chalk4.cyan(`src/tools/${answers.name}/index.ts`)} to implement your tool`,
991
+ `Add providers in ${chalk4.cyan(`src/tools/${answers.name}/providers/`)}`,
992
+ `Define types in ${chalk4.cyan(`src/tools/${answers.name}/types.ts`)}`,
993
+ answers.generateTests ? `Run ${chalk4.cyan(`pnpm test ${answers.name}`)} to test your tool` : "",
907
994
  `Register the tool in your agent's tool registry`
908
995
  ] : [
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` : "",
996
+ `Edit ${chalk4.cyan(`src/tools/${answers.name}.ts`)} to implement your tool`,
997
+ answers.generateTests ? `Run ${chalk4.cyan(`pnpm test tests/tools/${answers.name}.test.ts`)} to test your tool` : "",
911
998
  `Register the tool in your agent's tool registry`
912
999
  ];
913
1000
  logger.list(nextSteps.filter(Boolean));
@@ -967,8 +1054,8 @@ function capitalize2(str) {
967
1054
  return str.charAt(0).toUpperCase() + str.slice(1);
968
1055
  }
969
1056
  async function createSingleFileTool(cwd, answers) {
970
- const toolDir = path.join(cwd, "src", "tools");
971
- const toolFile = path.join(toolDir, `${answers.name}.ts`);
1057
+ const toolDir = path6.join(cwd, "src", "tools");
1058
+ const toolFile = path6.join(toolDir, `${answers.name}.ts`);
972
1059
  logger.startSpinner("Creating tool file...");
973
1060
  await ensureDir(toolDir);
974
1061
  const toolContent = generateToolContent(answers.name, answers.category, answers.description);
@@ -976,8 +1063,8 @@ async function createSingleFileTool(cwd, answers) {
976
1063
  logger.succeedSpinner("Tool file created");
977
1064
  if (answers.generateTests) {
978
1065
  logger.startSpinner("Creating test file...");
979
- const testDir = path.join(cwd, "tests", "tools");
980
- const testFile = path.join(testDir, `${answers.name}.test.ts`);
1066
+ const testDir = path6.join(cwd, "tests", "tools");
1067
+ const testFile = path6.join(testDir, `${answers.name}.test.ts`);
981
1068
  await ensureDir(testDir);
982
1069
  const testContent = generateTestContent2(answers.name);
983
1070
  await writeFile(testFile, testContent);
@@ -985,7 +1072,7 @@ async function createSingleFileTool(cwd, answers) {
985
1072
  }
986
1073
  }
987
1074
  async function createMultiFileTool(cwd, answers) {
988
- const toolDir = path.join(cwd, "src", "tools", answers.name);
1075
+ const toolDir = path6.join(cwd, "src", "tools", answers.name);
989
1076
  logger.startSpinner("Creating tool directory structure...");
990
1077
  await ensureDir(toolDir);
991
1078
  const templatePath = getTemplatePath("tool-multi");
@@ -1001,7 +1088,7 @@ async function createMultiFileTool(cwd, answers) {
1001
1088
  if (!answers.generateTests) {
1002
1089
  logger.startSpinner("Cleaning up test files...");
1003
1090
  const fs4 = await import('fs-extra');
1004
- const testDir = path.join(toolDir, "__tests__");
1091
+ const testDir = path6.join(toolDir, "__tests__");
1005
1092
  await fs4.remove(testDir);
1006
1093
  logger.succeedSpinner("Test files removed");
1007
1094
  }
@@ -1010,18 +1097,18 @@ async function toolListCommand(options) {
1010
1097
  try {
1011
1098
  logger.header("\u{1F4CB} List Tools");
1012
1099
  const cwd = process.cwd();
1013
- const toolDir = path.join(cwd, "src", "tools");
1100
+ const toolDir = path6.join(cwd, "src", "tools");
1014
1101
  const toolFiles = await findFiles("*.ts", toolDir);
1015
1102
  if (toolFiles.length === 0) {
1016
1103
  logger.warn("No tools found");
1017
- logger.info(`Create a tool with: ${chalk7.cyan("agentforge tool:create <name>")}`);
1104
+ logger.info(`Create a tool with: ${chalk4.cyan("agentforge tool:create <name>")}`);
1018
1105
  return;
1019
1106
  }
1020
1107
  let filteredTools = toolFiles;
1021
1108
  if (options.category) {
1022
1109
  filteredTools = [];
1023
1110
  for (const file of toolFiles) {
1024
- const toolPath = path.join(toolDir, file);
1111
+ const toolPath = path6.join(toolDir, file);
1025
1112
  const content = await readFile(toolPath);
1026
1113
  const category = extractCategory(content);
1027
1114
  if (category === options.category) {
@@ -1033,31 +1120,31 @@ async function toolListCommand(options) {
1033
1120
  logger.warn(`No tools found in category: ${options.category}`);
1034
1121
  return;
1035
1122
  }
1036
- logger.info(`Found ${chalk7.cyan(filteredTools.length)} tool(s):
1123
+ logger.info(`Found ${chalk4.cyan(filteredTools.length)} tool(s):
1037
1124
  `);
1038
1125
  for (const file of filteredTools) {
1039
- const toolName = path.basename(file, ".ts");
1040
- const toolPath = path.join(toolDir, file);
1126
+ const toolName = path6.basename(file, ".ts");
1127
+ const toolPath = path6.join(toolDir, file);
1041
1128
  if (options.verbose) {
1042
1129
  const content = await readFile(toolPath);
1043
1130
  const category = extractCategory(content);
1044
1131
  const description = extractDescription2(content);
1045
- logger.info(chalk7.bold.cyan(` ${toolName}`));
1132
+ logger.info(chalk4.bold.cyan(` ${toolName}`));
1046
1133
  if (category) {
1047
1134
  logger.info(` Category: ${category}`);
1048
1135
  }
1049
1136
  if (description) {
1050
1137
  logger.info(` Description: ${description}`);
1051
1138
  }
1052
- logger.info(` Path: ${chalk7.gray(toolPath)}`);
1139
+ logger.info(` Path: ${chalk4.gray(toolPath)}`);
1053
1140
  logger.newLine();
1054
1141
  } else {
1055
- logger.info(` \u2022 ${chalk7.cyan(toolName)}`);
1142
+ logger.info(` \u2022 ${chalk4.cyan(toolName)}`);
1056
1143
  }
1057
1144
  }
1058
1145
  if (!options.verbose) {
1059
1146
  logger.newLine();
1060
- logger.info(`Use ${chalk7.cyan("--verbose")} for more details`);
1147
+ logger.info(`Use ${chalk4.cyan("--verbose")} for more details`);
1061
1148
  }
1062
1149
  } catch (error) {
1063
1150
  logger.error(`Failed to list tools: ${error.message}`);
@@ -1076,13 +1163,13 @@ async function toolTestCommand(name, options) {
1076
1163
  try {
1077
1164
  logger.header("\u{1F9EA} Test Tool");
1078
1165
  const cwd = process.cwd();
1079
- const testFile = path.join(cwd, "tests", "tools", `${name}.test.ts`);
1166
+ const testFile = path6.join(cwd, "tests", "tools", `${name}.test.ts`);
1080
1167
  if (!await pathExists(testFile)) {
1081
1168
  logger.error(`Test file not found: ${testFile}`);
1082
- logger.info(`Create tests with: ${chalk7.cyan(`agentforge tool:create ${name} --test`)}`);
1169
+ logger.info(`Create tests with: ${chalk4.cyan(`agentforge tool:create ${name} --test`)}`);
1083
1170
  process.exit(1);
1084
1171
  }
1085
- logger.info(`Testing tool: ${chalk7.cyan(name)}`);
1172
+ logger.info(`Testing tool: ${chalk4.cyan(name)}`);
1086
1173
  logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
1087
1174
  logger.newLine();
1088
1175
  const packageManager = await detectPackageManager(cwd);
@@ -1100,8 +1187,8 @@ async function toolTestCommand(name, options) {
1100
1187
  async function toolPublishCommand(name, options) {
1101
1188
  try {
1102
1189
  logger.header("\u{1F4E6} Publish Tool");
1103
- logger.info(`Tool: ${chalk7.cyan(name)}`);
1104
- logger.info(`Tag: ${chalk7.cyan(options.tag || "latest")}`);
1190
+ logger.info(`Tool: ${chalk4.cyan(name)}`);
1191
+ logger.info(`Tag: ${chalk4.cyan(options.tag || "latest")}`);
1105
1192
  logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
1106
1193
  logger.newLine();
1107
1194
  if (options.dryRun) {
@@ -1133,7 +1220,7 @@ async function toolPublishCommand(name, options) {
1133
1220
  logger.succeedSpinner("Published to npm");
1134
1221
  }
1135
1222
  logger.newLine();
1136
- logger.success(chalk7.bold.green("\u2728 Tool published successfully!"));
1223
+ logger.success(chalk4.bold.green("\u2728 Tool published successfully!"));
1137
1224
  logger.newLine();
1138
1225
  logger.info("Note: Actual npm publishing implementation coming soon");
1139
1226
  logger.info("For now, please use npm publish manually");
@@ -1154,6 +1241,7 @@ program.command("test").description("Run tests with coverage").option("-w, --wat
1154
1241
  program.command("lint").description("Lint and format code").option("--fix", "Auto-fix issues").option("--no-format", "Skip formatting").action(lintCommand);
1155
1242
  var agent = program.command("agent").description("Manage agents");
1156
1243
  agent.command("create <name>").description("Create a new agent").option("-p, --pattern <pattern>", "Agent pattern (react, plan-execute, reflection, multi-agent)", "react").option("--no-test", "Skip test generation").action(agentCreateCommand);
1244
+ agent.command("create-reusable <name>").description("Create a new reusable agent (production template)").option("-d, --description <description>", "Agent description").option("-a, --author <author>", "Author name").action(agentCreateReusableCommand);
1157
1245
  agent.command("list").description("List all agents").option("-v, --verbose", "Show detailed information").action(agentListCommand);
1158
1246
  agent.command("test <name>").description("Test a specific agent").option("-w, --watch", "Watch mode").action(agentTestCommand);
1159
1247
  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);
@@ -1168,7 +1256,7 @@ async function run() {
1168
1256
  await program.parseAsync(process.argv);
1169
1257
  } catch (error) {
1170
1258
  if (error.code !== "commander.help" && error.code !== "commander.version") {
1171
- console.error(chalk7.red("Error:"), error.message);
1259
+ console.error(chalk4.red("Error:"), error.message);
1172
1260
  process.exit(1);
1173
1261
  }
1174
1262
  }