@agentforge/cli 0.5.0 → 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/README.md +51 -0
- package/dist/index.cjs +174 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +172 -84
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/api/package.json +2 -2
- package/templates/cli/package.json +2 -2
- package/templates/full/package.json +2 -2
- package/templates/minimal/package.json +2 -2
- package/templates/reusable-agent/README.md +148 -0
- package/templates/reusable-agent/index.test.ts +155 -0
- package/templates/reusable-agent/index.ts +147 -0
- package/templates/reusable-agent/package.json +35 -0
- package/templates/reusable-agent/prompt-loader.ts +43 -0
- package/templates/reusable-agent/prompts/system.md +28 -0
- package/templates/reusable-agent/tsconfig.json +10 -0
- package/templates/reusable-agent/vitest.config.ts +14 -0
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
-
import
|
|
3
|
-
import
|
|
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(
|
|
15
|
+
console.log(chalk4.blue("\u2139"), message);
|
|
16
16
|
}
|
|
17
17
|
success(message) {
|
|
18
|
-
console.log(
|
|
18
|
+
console.log(chalk4.green("\u2714"), message);
|
|
19
19
|
}
|
|
20
20
|
warn(message) {
|
|
21
|
-
console.log(
|
|
21
|
+
console.log(chalk4.yellow("\u26A0"), message);
|
|
22
22
|
}
|
|
23
23
|
error(message) {
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(chalk4.red("\u2716"), message);
|
|
25
25
|
}
|
|
26
26
|
debug(message) {
|
|
27
27
|
if (process.env.DEBUG) {
|
|
28
|
-
console.log(
|
|
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(
|
|
61
|
+
console.log(chalk4.gray("\u2500".repeat(50)));
|
|
62
62
|
}
|
|
63
63
|
header(message) {
|
|
64
64
|
this.newLine();
|
|
65
|
-
console.log(
|
|
65
|
+
console.log(chalk4.bold.cyan(message));
|
|
66
66
|
this.divider();
|
|
67
67
|
}
|
|
68
68
|
code(code) {
|
|
69
|
-
console.log(
|
|
69
|
+
console.log(chalk4.gray(" " + code));
|
|
70
70
|
}
|
|
71
71
|
list(items) {
|
|
72
72
|
items.forEach((item) => {
|
|
73
|
-
console.log(
|
|
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 =
|
|
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 =
|
|
272
|
-
const destPath =
|
|
273
|
-
await fs.ensureDir(
|
|
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(
|
|
297
|
+
await fs.ensureDir(path6.dirname(filePath));
|
|
298
298
|
await fs.writeFile(filePath, content);
|
|
299
299
|
}
|
|
300
300
|
function getTemplatePath(template) {
|
|
301
|
-
return
|
|
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(
|
|
311
|
+
if (await fs.pathExists(path6.join(cwd, "pnpm-lock.yaml"))) {
|
|
312
312
|
return "pnpm";
|
|
313
313
|
}
|
|
314
|
-
if (await fs.pathExists(
|
|
314
|
+
if (await fs.pathExists(path6.join(cwd, "yarn.lock"))) {
|
|
315
315
|
return "yarn";
|
|
316
316
|
}
|
|
317
|
-
if (await fs.pathExists(
|
|
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(
|
|
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 =
|
|
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: ${
|
|
443
|
-
logger.info(`Template: ${
|
|
444
|
-
logger.info(`Package manager: ${
|
|
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 =
|
|
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(
|
|
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: ${
|
|
630
|
-
logger.info(`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 =
|
|
634
|
-
const agentFile =
|
|
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 =
|
|
643
|
-
const testFile =
|
|
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(
|
|
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 ${
|
|
655
|
-
answers.generateTests ? `Run ${
|
|
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 =
|
|
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: ${
|
|
862
|
+
logger.info(`Create an agent with: ${chalk4.cyan("agentforge agent:create <name>")}`);
|
|
776
863
|
return;
|
|
777
864
|
}
|
|
778
|
-
logger.info(`Found ${
|
|
865
|
+
logger.info(`Found ${chalk4.cyan(agentFiles.length)} agent(s):
|
|
779
866
|
`);
|
|
780
867
|
for (const file of agentFiles) {
|
|
781
|
-
const agentName =
|
|
782
|
-
const agentPath =
|
|
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(
|
|
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: ${
|
|
881
|
+
logger.info(` Path: ${chalk4.gray(agentPath)}`);
|
|
795
882
|
logger.newLine();
|
|
796
883
|
} else {
|
|
797
|
-
logger.info(` \u2022 ${
|
|
884
|
+
logger.info(` \u2022 ${chalk4.cyan(agentName)}`);
|
|
798
885
|
}
|
|
799
886
|
}
|
|
800
887
|
if (!options.verbose) {
|
|
801
888
|
logger.newLine();
|
|
802
|
-
logger.info(`Use ${
|
|
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 =
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
851
|
-
logger.info(`Environment: ${
|
|
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(
|
|
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: ${
|
|
889
|
-
logger.info(`Category: ${
|
|
890
|
-
logger.info(`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(
|
|
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 ${
|
|
904
|
-
`Add providers in ${
|
|
905
|
-
`Define types in ${
|
|
906
|
-
answers.generateTests ? `Run ${
|
|
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 ${
|
|
910
|
-
answers.generateTests ? `Run ${
|
|
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 =
|
|
971
|
-
const toolFile =
|
|
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 =
|
|
980
|
-
const testFile =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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: ${
|
|
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 =
|
|
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 ${
|
|
1123
|
+
logger.info(`Found ${chalk4.cyan(filteredTools.length)} tool(s):
|
|
1037
1124
|
`);
|
|
1038
1125
|
for (const file of filteredTools) {
|
|
1039
|
-
const toolName =
|
|
1040
|
-
const toolPath =
|
|
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(
|
|
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: ${
|
|
1139
|
+
logger.info(` Path: ${chalk4.gray(toolPath)}`);
|
|
1053
1140
|
logger.newLine();
|
|
1054
1141
|
} else {
|
|
1055
|
-
logger.info(` \u2022 ${
|
|
1142
|
+
logger.info(` \u2022 ${chalk4.cyan(toolName)}`);
|
|
1056
1143
|
}
|
|
1057
1144
|
}
|
|
1058
1145
|
if (!options.verbose) {
|
|
1059
1146
|
logger.newLine();
|
|
1060
|
-
logger.info(`Use ${
|
|
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 =
|
|
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: ${
|
|
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: ${
|
|
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: ${
|
|
1104
|
-
logger.info(`Tag: ${
|
|
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(
|
|
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(
|
|
1259
|
+
console.error(chalk4.red("Error:"), error.message);
|
|
1172
1260
|
process.exit(1);
|
|
1173
1261
|
}
|
|
1174
1262
|
}
|