@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/README.md
CHANGED
|
@@ -135,6 +135,57 @@ agentforge agent:create myAgent --pattern plan-execute
|
|
|
135
135
|
- `-p, --pattern <pattern>` - Agent pattern (react, plan-execute, reflection, multi-agent) [default: react]
|
|
136
136
|
- `--no-test` - Skip test generation
|
|
137
137
|
|
|
138
|
+
#### `agent:create-reusable <name>`
|
|
139
|
+
|
|
140
|
+
Create a new reusable agent using the production template.
|
|
141
|
+
|
|
142
|
+
This command scaffolds a complete reusable agent with:
|
|
143
|
+
- Factory function pattern
|
|
144
|
+
- External prompt templates (`.md` files)
|
|
145
|
+
- Tool injection support
|
|
146
|
+
- Feature flags
|
|
147
|
+
- Configuration validation with Zod
|
|
148
|
+
- Comprehensive test suite
|
|
149
|
+
- Full documentation
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
agentforge agent:create-reusable customer-support
|
|
153
|
+
|
|
154
|
+
# With options
|
|
155
|
+
agentforge agent:create-reusable data-analyst --description "Analyze data and generate insights" --author "Your Name"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Options:**
|
|
159
|
+
- `-d, --description <description>` - Agent description
|
|
160
|
+
- `-a, --author <author>` - Author name
|
|
161
|
+
|
|
162
|
+
**What Gets Created:**
|
|
163
|
+
```
|
|
164
|
+
customer-support/
|
|
165
|
+
├── src/
|
|
166
|
+
│ ├── index.ts # Agent factory function
|
|
167
|
+
│ ├── index.test.ts # Comprehensive tests
|
|
168
|
+
│ └── prompt-loader.ts # Prompt template utility
|
|
169
|
+
├── prompts/
|
|
170
|
+
│ └── system.md # External prompt template
|
|
171
|
+
├── package.json
|
|
172
|
+
├── tsconfig.json
|
|
173
|
+
├── vitest.config.ts
|
|
174
|
+
└── README.md
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Next Steps After Creation:**
|
|
178
|
+
1. `cd customer-support`
|
|
179
|
+
2. `pnpm install`
|
|
180
|
+
3. Edit `prompts/system.md` to customize the prompt
|
|
181
|
+
4. Edit `src/index.ts` to add tools and configuration
|
|
182
|
+
5. `pnpm test` to run tests
|
|
183
|
+
6. `pnpm build` to build
|
|
184
|
+
|
|
185
|
+
**See Also:**
|
|
186
|
+
- [Reusable Agents Guide](../../docs-site/guide/advanced/reusable-agents.md)
|
|
187
|
+
- [Example Reusable Agents](../../examples/reusable-agents/)
|
|
188
|
+
|
|
138
189
|
#### `agent:list`
|
|
139
190
|
|
|
140
191
|
List all agents.
|
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var commander = require('commander');
|
|
4
|
-
var
|
|
5
|
-
var
|
|
4
|
+
var chalk4 = require('chalk');
|
|
5
|
+
var path6 = require('path');
|
|
6
6
|
var ora = require('ora');
|
|
7
7
|
var inquirer = require('inquirer');
|
|
8
8
|
var fs = require('fs-extra');
|
|
@@ -13,8 +13,8 @@ var execa = require('execa');
|
|
|
13
13
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
14
14
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
15
|
|
|
16
|
-
var
|
|
17
|
-
var
|
|
16
|
+
var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
|
|
17
|
+
var path6__default = /*#__PURE__*/_interopDefault(path6);
|
|
18
18
|
var ora__default = /*#__PURE__*/_interopDefault(ora);
|
|
19
19
|
var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
|
|
20
20
|
var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
@@ -23,20 +23,20 @@ var fs__default = /*#__PURE__*/_interopDefault(fs);
|
|
|
23
23
|
var Logger = class {
|
|
24
24
|
spinner = null;
|
|
25
25
|
info(message) {
|
|
26
|
-
console.log(
|
|
26
|
+
console.log(chalk4__default.default.blue("\u2139"), message);
|
|
27
27
|
}
|
|
28
28
|
success(message) {
|
|
29
|
-
console.log(
|
|
29
|
+
console.log(chalk4__default.default.green("\u2714"), message);
|
|
30
30
|
}
|
|
31
31
|
warn(message) {
|
|
32
|
-
console.log(
|
|
32
|
+
console.log(chalk4__default.default.yellow("\u26A0"), message);
|
|
33
33
|
}
|
|
34
34
|
error(message) {
|
|
35
|
-
console.log(
|
|
35
|
+
console.log(chalk4__default.default.red("\u2716"), message);
|
|
36
36
|
}
|
|
37
37
|
debug(message) {
|
|
38
38
|
if (process.env.DEBUG) {
|
|
39
|
-
console.log(
|
|
39
|
+
console.log(chalk4__default.default.gray("\u{1F41B}"), message);
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
startSpinner(message) {
|
|
@@ -69,19 +69,19 @@ var Logger = class {
|
|
|
69
69
|
console.log();
|
|
70
70
|
}
|
|
71
71
|
divider() {
|
|
72
|
-
console.log(
|
|
72
|
+
console.log(chalk4__default.default.gray("\u2500".repeat(50)));
|
|
73
73
|
}
|
|
74
74
|
header(message) {
|
|
75
75
|
this.newLine();
|
|
76
|
-
console.log(
|
|
76
|
+
console.log(chalk4__default.default.bold.cyan(message));
|
|
77
77
|
this.divider();
|
|
78
78
|
}
|
|
79
79
|
code(code) {
|
|
80
|
-
console.log(
|
|
80
|
+
console.log(chalk4__default.default.gray(" " + code));
|
|
81
81
|
}
|
|
82
82
|
list(items) {
|
|
83
83
|
items.forEach((item) => {
|
|
84
|
-
console.log(
|
|
84
|
+
console.log(chalk4__default.default.gray(" \u2022"), item);
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
};
|
|
@@ -261,7 +261,7 @@ async function promptToolSetup(defaults = {}) {
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
var __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
264
|
-
var __dirname$1 =
|
|
264
|
+
var __dirname$1 = path6__default.default.dirname(__filename$1);
|
|
265
265
|
async function ensureDir(dir) {
|
|
266
266
|
await fs__default.default.ensureDir(dir);
|
|
267
267
|
}
|
|
@@ -279,9 +279,9 @@ async function copyTemplate(templatePath, targetPath, replacements = {}) {
|
|
|
279
279
|
throw new Error(`No files found in template: ${templatePath}`);
|
|
280
280
|
}
|
|
281
281
|
for (const file of files) {
|
|
282
|
-
const sourcePath =
|
|
283
|
-
const destPath =
|
|
284
|
-
await fs__default.default.ensureDir(
|
|
282
|
+
const sourcePath = path6__default.default.join(templatePath, file);
|
|
283
|
+
const destPath = path6__default.default.join(targetPath, file);
|
|
284
|
+
await fs__default.default.ensureDir(path6__default.default.dirname(destPath));
|
|
285
285
|
let content = await fs__default.default.readFile(sourcePath, "utf-8");
|
|
286
286
|
for (const [key, value] of Object.entries(replacements)) {
|
|
287
287
|
content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
|
|
@@ -305,11 +305,11 @@ async function readFile(filePath) {
|
|
|
305
305
|
return fs__default.default.readFile(filePath, "utf-8");
|
|
306
306
|
}
|
|
307
307
|
async function writeFile(filePath, content) {
|
|
308
|
-
await fs__default.default.ensureDir(
|
|
308
|
+
await fs__default.default.ensureDir(path6__default.default.dirname(filePath));
|
|
309
309
|
await fs__default.default.writeFile(filePath, content);
|
|
310
310
|
}
|
|
311
311
|
function getTemplatePath(template) {
|
|
312
|
-
return
|
|
312
|
+
return path6__default.default.join(__dirname$1, "..", "templates", template);
|
|
313
313
|
}
|
|
314
314
|
async function isEmptyDir(dir) {
|
|
315
315
|
if (!await pathExists(dir)) {
|
|
@@ -319,13 +319,13 @@ async function isEmptyDir(dir) {
|
|
|
319
319
|
return files.length === 0;
|
|
320
320
|
}
|
|
321
321
|
async function detectPackageManager(cwd = process.cwd()) {
|
|
322
|
-
if (await fs__default.default.pathExists(
|
|
322
|
+
if (await fs__default.default.pathExists(path6__default.default.join(cwd, "pnpm-lock.yaml"))) {
|
|
323
323
|
return "pnpm";
|
|
324
324
|
}
|
|
325
|
-
if (await fs__default.default.pathExists(
|
|
325
|
+
if (await fs__default.default.pathExists(path6__default.default.join(cwd, "yarn.lock"))) {
|
|
326
326
|
return "yarn";
|
|
327
327
|
}
|
|
328
|
-
if (await fs__default.default.pathExists(
|
|
328
|
+
if (await fs__default.default.pathExists(path6__default.default.join(cwd, "package-lock.json"))) {
|
|
329
329
|
return "npm";
|
|
330
330
|
}
|
|
331
331
|
try {
|
|
@@ -422,7 +422,7 @@ pnpm-debug.log*
|
|
|
422
422
|
.temp/
|
|
423
423
|
.tmp/
|
|
424
424
|
`;
|
|
425
|
-
await fs__default.default.writeFile(
|
|
425
|
+
await fs__default.default.writeFile(path6__default.default.join(cwd, ".gitignore"), gitignore);
|
|
426
426
|
}
|
|
427
427
|
async function createInitialCommit(cwd) {
|
|
428
428
|
await execa.execa("git", ["add", "."], { cwd });
|
|
@@ -437,7 +437,7 @@ async function createCommand(projectName, options) {
|
|
|
437
437
|
logger.error("Project name is required");
|
|
438
438
|
process.exit(1);
|
|
439
439
|
}
|
|
440
|
-
const targetPath =
|
|
440
|
+
const targetPath = path6__default.default.join(process.cwd(), projectName);
|
|
441
441
|
if (!await isEmptyDir(targetPath)) {
|
|
442
442
|
logger.error(`Directory ${projectName} already exists and is not empty`);
|
|
443
443
|
process.exit(1);
|
|
@@ -450,9 +450,9 @@ async function createCommand(projectName, options) {
|
|
|
450
450
|
initGit: options.git
|
|
451
451
|
});
|
|
452
452
|
logger.newLine();
|
|
453
|
-
logger.info(`Creating project: ${
|
|
454
|
-
logger.info(`Template: ${
|
|
455
|
-
logger.info(`Package manager: ${
|
|
453
|
+
logger.info(`Creating project: ${chalk4__default.default.cyan(answers.projectName)}`);
|
|
454
|
+
logger.info(`Template: ${chalk4__default.default.cyan(answers.template)}`);
|
|
455
|
+
logger.info(`Package manager: ${chalk4__default.default.cyan(answers.packageManager)}`);
|
|
456
456
|
logger.newLine();
|
|
457
457
|
logger.startSpinner("Creating project directory...");
|
|
458
458
|
await ensureDir(targetPath);
|
|
@@ -467,7 +467,7 @@ async function createCommand(projectName, options) {
|
|
|
467
467
|
});
|
|
468
468
|
logger.succeedSpinner("Template files copied");
|
|
469
469
|
logger.startSpinner("Updating package.json...");
|
|
470
|
-
const packageJsonPath =
|
|
470
|
+
const packageJsonPath = path6__default.default.join(targetPath, "package.json");
|
|
471
471
|
const packageJson = await readJson(packageJsonPath);
|
|
472
472
|
packageJson.name = answers.projectName;
|
|
473
473
|
if (answers.author) {
|
|
@@ -500,7 +500,7 @@ async function createCommand(projectName, options) {
|
|
|
500
500
|
}
|
|
501
501
|
}
|
|
502
502
|
logger.newLine();
|
|
503
|
-
logger.success(
|
|
503
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Project created successfully!"));
|
|
504
504
|
logger.newLine();
|
|
505
505
|
logger.header("\u{1F4DD} Next Steps");
|
|
506
506
|
logger.list([
|
|
@@ -637,12 +637,12 @@ async function agentCreateCommand(name, options) {
|
|
|
637
637
|
generateTests: options.test
|
|
638
638
|
});
|
|
639
639
|
logger.newLine();
|
|
640
|
-
logger.info(`Creating agent: ${
|
|
641
|
-
logger.info(`Pattern: ${
|
|
640
|
+
logger.info(`Creating agent: ${chalk4__default.default.cyan(answers.name)}`);
|
|
641
|
+
logger.info(`Pattern: ${chalk4__default.default.cyan(answers.pattern)}`);
|
|
642
642
|
logger.newLine();
|
|
643
643
|
const cwd = process.cwd();
|
|
644
|
-
const agentDir =
|
|
645
|
-
const agentFile =
|
|
644
|
+
const agentDir = path6__default.default.join(cwd, "src", "agents");
|
|
645
|
+
const agentFile = path6__default.default.join(agentDir, `${answers.name}.ts`);
|
|
646
646
|
logger.startSpinner("Creating agent file...");
|
|
647
647
|
await ensureDir(agentDir);
|
|
648
648
|
const agentContent = generateAgentContent(answers.name, answers.pattern, answers.description);
|
|
@@ -650,20 +650,20 @@ async function agentCreateCommand(name, options) {
|
|
|
650
650
|
logger.succeedSpinner("Agent file created");
|
|
651
651
|
if (answers.generateTests) {
|
|
652
652
|
logger.startSpinner("Creating test file...");
|
|
653
|
-
const testDir =
|
|
654
|
-
const testFile =
|
|
653
|
+
const testDir = path6__default.default.join(cwd, "tests", "agents");
|
|
654
|
+
const testFile = path6__default.default.join(testDir, `${answers.name}.test.ts`);
|
|
655
655
|
await ensureDir(testDir);
|
|
656
656
|
const testContent = generateTestContent(answers.name, answers.pattern);
|
|
657
657
|
await writeFile(testFile, testContent);
|
|
658
658
|
logger.succeedSpinner("Test file created");
|
|
659
659
|
}
|
|
660
660
|
logger.newLine();
|
|
661
|
-
logger.success(
|
|
661
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Agent created successfully!"));
|
|
662
662
|
logger.newLine();
|
|
663
663
|
logger.header("\u{1F4DD} Next Steps");
|
|
664
664
|
logger.list([
|
|
665
|
-
`Edit ${
|
|
666
|
-
answers.generateTests ? `Run ${
|
|
665
|
+
`Edit ${chalk4__default.default.cyan(`src/agents/${answers.name}.ts`)} to customize your agent`,
|
|
666
|
+
answers.generateTests ? `Run ${chalk4__default.default.cyan(`pnpm test tests/agents/${answers.name}.test.ts`)} to test your agent` : ""
|
|
667
667
|
].filter(Boolean));
|
|
668
668
|
} catch (error) {
|
|
669
669
|
logger.error(`Failed to create agent: ${error.message}`);
|
|
@@ -775,42 +775,129 @@ describe('${capitalize(name)} ${pattern === "multi-agent" ? "System" : "Agent"}'
|
|
|
775
775
|
function capitalize(str) {
|
|
776
776
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
777
777
|
}
|
|
778
|
+
async function agentCreateReusableCommand(name, options) {
|
|
779
|
+
try {
|
|
780
|
+
logger.header("\u{1F4E6} Create Reusable Agent");
|
|
781
|
+
const answers = await inquirer__default.default.prompt([
|
|
782
|
+
{
|
|
783
|
+
type: "input",
|
|
784
|
+
name: "name",
|
|
785
|
+
message: "Agent name (e.g., customer-support):",
|
|
786
|
+
default: name,
|
|
787
|
+
validate: (input) => {
|
|
788
|
+
if (!input) return "Agent name is required";
|
|
789
|
+
if (!/^[a-z][a-z0-9-]*$/.test(input)) {
|
|
790
|
+
return "Agent name must be lowercase with hyphens (e.g., customer-support)";
|
|
791
|
+
}
|
|
792
|
+
return true;
|
|
793
|
+
}
|
|
794
|
+
},
|
|
795
|
+
{
|
|
796
|
+
type: "input",
|
|
797
|
+
name: "description",
|
|
798
|
+
message: "Agent description:",
|
|
799
|
+
default: options.description || `A reusable ${name} agent`
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
type: "input",
|
|
803
|
+
name: "author",
|
|
804
|
+
message: "Author name:",
|
|
805
|
+
default: options.author || ""
|
|
806
|
+
}
|
|
807
|
+
]);
|
|
808
|
+
logger.newLine();
|
|
809
|
+
logger.info(`Creating reusable agent: ${chalk4__default.default.cyan(answers.name)}`);
|
|
810
|
+
logger.info(`Description: ${chalk4__default.default.gray(answers.description)}`);
|
|
811
|
+
logger.newLine();
|
|
812
|
+
const cwd = process.cwd();
|
|
813
|
+
const agentDir = path6__default.default.join(cwd, answers.name);
|
|
814
|
+
const agentNameKebab = answers.name;
|
|
815
|
+
const agentNamePascal = kebabToPascal(agentNameKebab);
|
|
816
|
+
const agentNameCamel = kebabToCamel(agentNameKebab);
|
|
817
|
+
const packageName = `@agentforge/${agentNameKebab}`;
|
|
818
|
+
const replacements = {
|
|
819
|
+
AGENT_NAME_KEBAB: agentNameKebab,
|
|
820
|
+
AGENT_NAME_PASCAL: agentNamePascal,
|
|
821
|
+
AGENT_NAME_CAMEL: agentNameCamel,
|
|
822
|
+
AGENT_DESCRIPTION: answers.description,
|
|
823
|
+
PACKAGE_NAME: packageName,
|
|
824
|
+
AUTHOR: answers.author || "Your Name"
|
|
825
|
+
};
|
|
826
|
+
logger.startSpinner("Creating agent structure...");
|
|
827
|
+
const templatePath = getTemplatePath("reusable-agent");
|
|
828
|
+
await copyTemplate(templatePath, agentDir, replacements);
|
|
829
|
+
logger.succeedSpinner("Agent structure created");
|
|
830
|
+
logger.startSpinner("Organizing files...");
|
|
831
|
+
const fs4 = await import('fs-extra');
|
|
832
|
+
const srcDir = path6__default.default.join(agentDir, "src");
|
|
833
|
+
await fs4.ensureDir(srcDir);
|
|
834
|
+
await fs4.move(path6__default.default.join(agentDir, "index.ts"), path6__default.default.join(srcDir, "index.ts"));
|
|
835
|
+
await fs4.move(path6__default.default.join(agentDir, "prompt-loader.ts"), path6__default.default.join(srcDir, "prompt-loader.ts"));
|
|
836
|
+
await fs4.move(path6__default.default.join(agentDir, "index.test.ts"), path6__default.default.join(srcDir, "index.test.ts"));
|
|
837
|
+
logger.succeedSpinner("Files organized");
|
|
838
|
+
logger.newLine();
|
|
839
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Reusable agent created successfully!"));
|
|
840
|
+
logger.newLine();
|
|
841
|
+
logger.header("\u{1F4DD} Next Steps");
|
|
842
|
+
const nextSteps = [
|
|
843
|
+
`cd ${chalk4__default.default.cyan(answers.name)}`,
|
|
844
|
+
`Install dependencies: ${chalk4__default.default.cyan("pnpm install")}`,
|
|
845
|
+
`Edit ${chalk4__default.default.cyan("prompts/system.md")} to customize the agent prompt`,
|
|
846
|
+
`Edit ${chalk4__default.default.cyan("src/index.ts")} to add tools and configuration`,
|
|
847
|
+
`Run tests: ${chalk4__default.default.cyan("pnpm test")}`,
|
|
848
|
+
`Build: ${chalk4__default.default.cyan("pnpm build")}`
|
|
849
|
+
];
|
|
850
|
+
logger.list(nextSteps);
|
|
851
|
+
logger.newLine();
|
|
852
|
+
logger.info(chalk4__default.default.gray("\u{1F4A1} Tip: See examples/reusable-agents/ for reference implementations"));
|
|
853
|
+
} catch (error) {
|
|
854
|
+
logger.error(`Failed to create reusable agent: ${error.message}`);
|
|
855
|
+
process.exit(1);
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
function kebabToPascal(str) {
|
|
859
|
+
return str.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
|
|
860
|
+
}
|
|
861
|
+
function kebabToCamel(str) {
|
|
862
|
+
const pascal = kebabToPascal(str);
|
|
863
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
864
|
+
}
|
|
778
865
|
async function agentListCommand(options) {
|
|
779
866
|
try {
|
|
780
867
|
logger.header("\u{1F4CB} List Agents");
|
|
781
868
|
const cwd = process.cwd();
|
|
782
|
-
const agentDir =
|
|
869
|
+
const agentDir = path6__default.default.join(cwd, "src", "agents");
|
|
783
870
|
const agentFiles = await findFiles("*.ts", agentDir);
|
|
784
871
|
if (agentFiles.length === 0) {
|
|
785
872
|
logger.warn("No agents found");
|
|
786
|
-
logger.info(`Create an agent with: ${
|
|
873
|
+
logger.info(`Create an agent with: ${chalk4__default.default.cyan("agentforge agent:create <name>")}`);
|
|
787
874
|
return;
|
|
788
875
|
}
|
|
789
|
-
logger.info(`Found ${
|
|
876
|
+
logger.info(`Found ${chalk4__default.default.cyan(agentFiles.length)} agent(s):
|
|
790
877
|
`);
|
|
791
878
|
for (const file of agentFiles) {
|
|
792
|
-
const agentName =
|
|
793
|
-
const agentPath =
|
|
879
|
+
const agentName = path6__default.default.basename(file, ".ts");
|
|
880
|
+
const agentPath = path6__default.default.join(agentDir, file);
|
|
794
881
|
if (options.verbose) {
|
|
795
882
|
const content = await readFile(agentPath);
|
|
796
883
|
const pattern = extractPattern(content);
|
|
797
884
|
const description = extractDescription(content);
|
|
798
|
-
logger.info(
|
|
885
|
+
logger.info(chalk4__default.default.bold.cyan(` ${agentName}`));
|
|
799
886
|
if (pattern) {
|
|
800
887
|
logger.info(` Pattern: ${pattern}`);
|
|
801
888
|
}
|
|
802
889
|
if (description) {
|
|
803
890
|
logger.info(` Description: ${description}`);
|
|
804
891
|
}
|
|
805
|
-
logger.info(` Path: ${
|
|
892
|
+
logger.info(` Path: ${chalk4__default.default.gray(agentPath)}`);
|
|
806
893
|
logger.newLine();
|
|
807
894
|
} else {
|
|
808
|
-
logger.info(` \u2022 ${
|
|
895
|
+
logger.info(` \u2022 ${chalk4__default.default.cyan(agentName)}`);
|
|
809
896
|
}
|
|
810
897
|
}
|
|
811
898
|
if (!options.verbose) {
|
|
812
899
|
logger.newLine();
|
|
813
|
-
logger.info(`Use ${
|
|
900
|
+
logger.info(`Use ${chalk4__default.default.cyan("--verbose")} for more details`);
|
|
814
901
|
}
|
|
815
902
|
} catch (error) {
|
|
816
903
|
logger.error(`Failed to list agents: ${error.message}`);
|
|
@@ -834,13 +921,13 @@ async function agentTestCommand(name, options) {
|
|
|
834
921
|
try {
|
|
835
922
|
logger.header("\u{1F9EA} Test Agent");
|
|
836
923
|
const cwd = process.cwd();
|
|
837
|
-
const testFile =
|
|
924
|
+
const testFile = path6__default.default.join(cwd, "tests", "agents", `${name}.test.ts`);
|
|
838
925
|
if (!await pathExists(testFile)) {
|
|
839
926
|
logger.error(`Test file not found: ${testFile}`);
|
|
840
|
-
logger.info(`Create tests with: ${
|
|
927
|
+
logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge agent:create ${name} --test`)}`);
|
|
841
928
|
process.exit(1);
|
|
842
929
|
}
|
|
843
|
-
logger.info(`Testing agent: ${
|
|
930
|
+
logger.info(`Testing agent: ${chalk4__default.default.cyan(name)}`);
|
|
844
931
|
logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
|
|
845
932
|
logger.newLine();
|
|
846
933
|
const packageManager = await detectPackageManager(cwd);
|
|
@@ -858,8 +945,8 @@ async function agentTestCommand(name, options) {
|
|
|
858
945
|
async function agentDeployCommand(name, options) {
|
|
859
946
|
try {
|
|
860
947
|
logger.header("\u{1F680} Deploy Agent");
|
|
861
|
-
logger.info(`Agent: ${
|
|
862
|
-
logger.info(`Environment: ${
|
|
948
|
+
logger.info(`Agent: ${chalk4__default.default.cyan(name)}`);
|
|
949
|
+
logger.info(`Environment: ${chalk4__default.default.cyan(options.environment || "production")}`);
|
|
863
950
|
logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
|
|
864
951
|
logger.newLine();
|
|
865
952
|
if (options.dryRun) {
|
|
@@ -875,7 +962,7 @@ async function agentDeployCommand(name, options) {
|
|
|
875
962
|
logger.succeedSpinner("Agent deployed successfully");
|
|
876
963
|
}
|
|
877
964
|
logger.newLine();
|
|
878
|
-
logger.success(
|
|
965
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Deployment completed!"));
|
|
879
966
|
logger.newLine();
|
|
880
967
|
logger.info("Note: Actual deployment implementation coming soon");
|
|
881
968
|
logger.info("For now, please use the deployment templates in the templates/deployment directory");
|
|
@@ -896,9 +983,9 @@ async function toolCreateCommand(name, options) {
|
|
|
896
983
|
generateTests: options.test
|
|
897
984
|
});
|
|
898
985
|
logger.newLine();
|
|
899
|
-
logger.info(`Creating tool: ${
|
|
900
|
-
logger.info(`Category: ${
|
|
901
|
-
logger.info(`Structure: ${
|
|
986
|
+
logger.info(`Creating tool: ${chalk4__default.default.cyan(answers.name)}`);
|
|
987
|
+
logger.info(`Category: ${chalk4__default.default.cyan(answers.category)}`);
|
|
988
|
+
logger.info(`Structure: ${chalk4__default.default.cyan(answers.structure)}`);
|
|
902
989
|
logger.newLine();
|
|
903
990
|
const cwd = process.cwd();
|
|
904
991
|
if (answers.structure === "multi") {
|
|
@@ -907,18 +994,18 @@ async function toolCreateCommand(name, options) {
|
|
|
907
994
|
await createSingleFileTool(cwd, answers);
|
|
908
995
|
}
|
|
909
996
|
logger.newLine();
|
|
910
|
-
logger.success(
|
|
997
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Tool created successfully!"));
|
|
911
998
|
logger.newLine();
|
|
912
999
|
logger.header("\u{1F4DD} Next Steps");
|
|
913
1000
|
const nextSteps = answers.structure === "multi" ? [
|
|
914
|
-
`Edit ${
|
|
915
|
-
`Add providers in ${
|
|
916
|
-
`Define types in ${
|
|
917
|
-
answers.generateTests ? `Run ${
|
|
1001
|
+
`Edit ${chalk4__default.default.cyan(`src/tools/${answers.name}/index.ts`)} to implement your tool`,
|
|
1002
|
+
`Add providers in ${chalk4__default.default.cyan(`src/tools/${answers.name}/providers/`)}`,
|
|
1003
|
+
`Define types in ${chalk4__default.default.cyan(`src/tools/${answers.name}/types.ts`)}`,
|
|
1004
|
+
answers.generateTests ? `Run ${chalk4__default.default.cyan(`pnpm test ${answers.name}`)} to test your tool` : "",
|
|
918
1005
|
`Register the tool in your agent's tool registry`
|
|
919
1006
|
] : [
|
|
920
|
-
`Edit ${
|
|
921
|
-
answers.generateTests ? `Run ${
|
|
1007
|
+
`Edit ${chalk4__default.default.cyan(`src/tools/${answers.name}.ts`)} to implement your tool`,
|
|
1008
|
+
answers.generateTests ? `Run ${chalk4__default.default.cyan(`pnpm test tests/tools/${answers.name}.test.ts`)} to test your tool` : "",
|
|
922
1009
|
`Register the tool in your agent's tool registry`
|
|
923
1010
|
];
|
|
924
1011
|
logger.list(nextSteps.filter(Boolean));
|
|
@@ -978,8 +1065,8 @@ function capitalize2(str) {
|
|
|
978
1065
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
979
1066
|
}
|
|
980
1067
|
async function createSingleFileTool(cwd, answers) {
|
|
981
|
-
const toolDir =
|
|
982
|
-
const toolFile =
|
|
1068
|
+
const toolDir = path6__default.default.join(cwd, "src", "tools");
|
|
1069
|
+
const toolFile = path6__default.default.join(toolDir, `${answers.name}.ts`);
|
|
983
1070
|
logger.startSpinner("Creating tool file...");
|
|
984
1071
|
await ensureDir(toolDir);
|
|
985
1072
|
const toolContent = generateToolContent(answers.name, answers.category, answers.description);
|
|
@@ -987,8 +1074,8 @@ async function createSingleFileTool(cwd, answers) {
|
|
|
987
1074
|
logger.succeedSpinner("Tool file created");
|
|
988
1075
|
if (answers.generateTests) {
|
|
989
1076
|
logger.startSpinner("Creating test file...");
|
|
990
|
-
const testDir =
|
|
991
|
-
const testFile =
|
|
1077
|
+
const testDir = path6__default.default.join(cwd, "tests", "tools");
|
|
1078
|
+
const testFile = path6__default.default.join(testDir, `${answers.name}.test.ts`);
|
|
992
1079
|
await ensureDir(testDir);
|
|
993
1080
|
const testContent = generateTestContent2(answers.name);
|
|
994
1081
|
await writeFile(testFile, testContent);
|
|
@@ -996,7 +1083,7 @@ async function createSingleFileTool(cwd, answers) {
|
|
|
996
1083
|
}
|
|
997
1084
|
}
|
|
998
1085
|
async function createMultiFileTool(cwd, answers) {
|
|
999
|
-
const toolDir =
|
|
1086
|
+
const toolDir = path6__default.default.join(cwd, "src", "tools", answers.name);
|
|
1000
1087
|
logger.startSpinner("Creating tool directory structure...");
|
|
1001
1088
|
await ensureDir(toolDir);
|
|
1002
1089
|
const templatePath = getTemplatePath("tool-multi");
|
|
@@ -1012,7 +1099,7 @@ async function createMultiFileTool(cwd, answers) {
|
|
|
1012
1099
|
if (!answers.generateTests) {
|
|
1013
1100
|
logger.startSpinner("Cleaning up test files...");
|
|
1014
1101
|
const fs4 = await import('fs-extra');
|
|
1015
|
-
const testDir =
|
|
1102
|
+
const testDir = path6__default.default.join(toolDir, "__tests__");
|
|
1016
1103
|
await fs4.remove(testDir);
|
|
1017
1104
|
logger.succeedSpinner("Test files removed");
|
|
1018
1105
|
}
|
|
@@ -1021,18 +1108,18 @@ async function toolListCommand(options) {
|
|
|
1021
1108
|
try {
|
|
1022
1109
|
logger.header("\u{1F4CB} List Tools");
|
|
1023
1110
|
const cwd = process.cwd();
|
|
1024
|
-
const toolDir =
|
|
1111
|
+
const toolDir = path6__default.default.join(cwd, "src", "tools");
|
|
1025
1112
|
const toolFiles = await findFiles("*.ts", toolDir);
|
|
1026
1113
|
if (toolFiles.length === 0) {
|
|
1027
1114
|
logger.warn("No tools found");
|
|
1028
|
-
logger.info(`Create a tool with: ${
|
|
1115
|
+
logger.info(`Create a tool with: ${chalk4__default.default.cyan("agentforge tool:create <name>")}`);
|
|
1029
1116
|
return;
|
|
1030
1117
|
}
|
|
1031
1118
|
let filteredTools = toolFiles;
|
|
1032
1119
|
if (options.category) {
|
|
1033
1120
|
filteredTools = [];
|
|
1034
1121
|
for (const file of toolFiles) {
|
|
1035
|
-
const toolPath =
|
|
1122
|
+
const toolPath = path6__default.default.join(toolDir, file);
|
|
1036
1123
|
const content = await readFile(toolPath);
|
|
1037
1124
|
const category = extractCategory(content);
|
|
1038
1125
|
if (category === options.category) {
|
|
@@ -1044,31 +1131,31 @@ async function toolListCommand(options) {
|
|
|
1044
1131
|
logger.warn(`No tools found in category: ${options.category}`);
|
|
1045
1132
|
return;
|
|
1046
1133
|
}
|
|
1047
|
-
logger.info(`Found ${
|
|
1134
|
+
logger.info(`Found ${chalk4__default.default.cyan(filteredTools.length)} tool(s):
|
|
1048
1135
|
`);
|
|
1049
1136
|
for (const file of filteredTools) {
|
|
1050
|
-
const toolName =
|
|
1051
|
-
const toolPath =
|
|
1137
|
+
const toolName = path6__default.default.basename(file, ".ts");
|
|
1138
|
+
const toolPath = path6__default.default.join(toolDir, file);
|
|
1052
1139
|
if (options.verbose) {
|
|
1053
1140
|
const content = await readFile(toolPath);
|
|
1054
1141
|
const category = extractCategory(content);
|
|
1055
1142
|
const description = extractDescription2(content);
|
|
1056
|
-
logger.info(
|
|
1143
|
+
logger.info(chalk4__default.default.bold.cyan(` ${toolName}`));
|
|
1057
1144
|
if (category) {
|
|
1058
1145
|
logger.info(` Category: ${category}`);
|
|
1059
1146
|
}
|
|
1060
1147
|
if (description) {
|
|
1061
1148
|
logger.info(` Description: ${description}`);
|
|
1062
1149
|
}
|
|
1063
|
-
logger.info(` Path: ${
|
|
1150
|
+
logger.info(` Path: ${chalk4__default.default.gray(toolPath)}`);
|
|
1064
1151
|
logger.newLine();
|
|
1065
1152
|
} else {
|
|
1066
|
-
logger.info(` \u2022 ${
|
|
1153
|
+
logger.info(` \u2022 ${chalk4__default.default.cyan(toolName)}`);
|
|
1067
1154
|
}
|
|
1068
1155
|
}
|
|
1069
1156
|
if (!options.verbose) {
|
|
1070
1157
|
logger.newLine();
|
|
1071
|
-
logger.info(`Use ${
|
|
1158
|
+
logger.info(`Use ${chalk4__default.default.cyan("--verbose")} for more details`);
|
|
1072
1159
|
}
|
|
1073
1160
|
} catch (error) {
|
|
1074
1161
|
logger.error(`Failed to list tools: ${error.message}`);
|
|
@@ -1087,13 +1174,13 @@ async function toolTestCommand(name, options) {
|
|
|
1087
1174
|
try {
|
|
1088
1175
|
logger.header("\u{1F9EA} Test Tool");
|
|
1089
1176
|
const cwd = process.cwd();
|
|
1090
|
-
const testFile =
|
|
1177
|
+
const testFile = path6__default.default.join(cwd, "tests", "tools", `${name}.test.ts`);
|
|
1091
1178
|
if (!await pathExists(testFile)) {
|
|
1092
1179
|
logger.error(`Test file not found: ${testFile}`);
|
|
1093
|
-
logger.info(`Create tests with: ${
|
|
1180
|
+
logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge tool:create ${name} --test`)}`);
|
|
1094
1181
|
process.exit(1);
|
|
1095
1182
|
}
|
|
1096
|
-
logger.info(`Testing tool: ${
|
|
1183
|
+
logger.info(`Testing tool: ${chalk4__default.default.cyan(name)}`);
|
|
1097
1184
|
logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
|
|
1098
1185
|
logger.newLine();
|
|
1099
1186
|
const packageManager = await detectPackageManager(cwd);
|
|
@@ -1111,8 +1198,8 @@ async function toolTestCommand(name, options) {
|
|
|
1111
1198
|
async function toolPublishCommand(name, options) {
|
|
1112
1199
|
try {
|
|
1113
1200
|
logger.header("\u{1F4E6} Publish Tool");
|
|
1114
|
-
logger.info(`Tool: ${
|
|
1115
|
-
logger.info(`Tag: ${
|
|
1201
|
+
logger.info(`Tool: ${chalk4__default.default.cyan(name)}`);
|
|
1202
|
+
logger.info(`Tag: ${chalk4__default.default.cyan(options.tag || "latest")}`);
|
|
1116
1203
|
logger.info(`Dry run: ${options.dryRun ? "Yes" : "No"}`);
|
|
1117
1204
|
logger.newLine();
|
|
1118
1205
|
if (options.dryRun) {
|
|
@@ -1144,7 +1231,7 @@ async function toolPublishCommand(name, options) {
|
|
|
1144
1231
|
logger.succeedSpinner("Published to npm");
|
|
1145
1232
|
}
|
|
1146
1233
|
logger.newLine();
|
|
1147
|
-
logger.success(
|
|
1234
|
+
logger.success(chalk4__default.default.bold.green("\u2728 Tool published successfully!"));
|
|
1148
1235
|
logger.newLine();
|
|
1149
1236
|
logger.info("Note: Actual npm publishing implementation coming soon");
|
|
1150
1237
|
logger.info("For now, please use npm publish manually");
|
|
@@ -1165,6 +1252,7 @@ program.command("test").description("Run tests with coverage").option("-w, --wat
|
|
|
1165
1252
|
program.command("lint").description("Lint and format code").option("--fix", "Auto-fix issues").option("--no-format", "Skip formatting").action(lintCommand);
|
|
1166
1253
|
var agent = program.command("agent").description("Manage agents");
|
|
1167
1254
|
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);
|
|
1255
|
+
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);
|
|
1168
1256
|
agent.command("list").description("List all agents").option("-v, --verbose", "Show detailed information").action(agentListCommand);
|
|
1169
1257
|
agent.command("test <name>").description("Test a specific agent").option("-w, --watch", "Watch mode").action(agentTestCommand);
|
|
1170
1258
|
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);
|
|
@@ -1179,7 +1267,7 @@ async function run() {
|
|
|
1179
1267
|
await program.parseAsync(process.argv);
|
|
1180
1268
|
} catch (error) {
|
|
1181
1269
|
if (error.code !== "commander.help" && error.code !== "commander.version") {
|
|
1182
|
-
console.error(
|
|
1270
|
+
console.error(chalk4__default.default.red("Error:"), error.message);
|
|
1183
1271
|
process.exit(1);
|
|
1184
1272
|
}
|
|
1185
1273
|
}
|