@agentforge/cli 0.18.1 → 0.18.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +67 -72
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +66 -71
- 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/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk4 from 'chalk';
|
|
3
|
-
import
|
|
3
|
+
import path11 from 'path';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import fs from 'fs-extra';
|
|
@@ -274,7 +274,7 @@ async function promptToolSetup(defaults = {}) {
|
|
|
274
274
|
};
|
|
275
275
|
}
|
|
276
276
|
var __filename$1 = fileURLToPath(import.meta.url);
|
|
277
|
-
var __dirname$1 =
|
|
277
|
+
var __dirname$1 = path11.dirname(__filename$1);
|
|
278
278
|
async function ensureDir(dir) {
|
|
279
279
|
await fs.ensureDir(dir);
|
|
280
280
|
}
|
|
@@ -292,9 +292,9 @@ async function copyTemplate(templatePath, targetPath, replacements = {}) {
|
|
|
292
292
|
throw new Error(`No files found in template: ${templatePath}`);
|
|
293
293
|
}
|
|
294
294
|
for (const file of files) {
|
|
295
|
-
const sourcePath =
|
|
296
|
-
const destPath =
|
|
297
|
-
await fs.ensureDir(
|
|
295
|
+
const sourcePath = path11.join(templatePath, file);
|
|
296
|
+
const destPath = path11.join(targetPath, file);
|
|
297
|
+
await fs.ensureDir(path11.dirname(destPath));
|
|
298
298
|
let content = await fs.readFile(sourcePath, "utf-8");
|
|
299
299
|
for (const [key, value] of Object.entries(replacements)) {
|
|
300
300
|
content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
|
|
@@ -318,11 +318,11 @@ async function readFile(filePath) {
|
|
|
318
318
|
return fs.readFile(filePath, "utf-8");
|
|
319
319
|
}
|
|
320
320
|
async function writeFile(filePath, content) {
|
|
321
|
-
await fs.ensureDir(
|
|
321
|
+
await fs.ensureDir(path11.dirname(filePath));
|
|
322
322
|
await fs.writeFile(filePath, content);
|
|
323
323
|
}
|
|
324
324
|
function getTemplatePath(template) {
|
|
325
|
-
return
|
|
325
|
+
return path11.join(__dirname$1, "..", "templates", template);
|
|
326
326
|
}
|
|
327
327
|
async function isEmptyDir(dir) {
|
|
328
328
|
if (!await pathExists(dir)) {
|
|
@@ -332,13 +332,13 @@ async function isEmptyDir(dir) {
|
|
|
332
332
|
return files.length === 0;
|
|
333
333
|
}
|
|
334
334
|
async function detectPackageManager(cwd = process.cwd()) {
|
|
335
|
-
if (await fs.pathExists(
|
|
335
|
+
if (await fs.pathExists(path11.join(cwd, "pnpm-lock.yaml"))) {
|
|
336
336
|
return "pnpm";
|
|
337
337
|
}
|
|
338
|
-
if (await fs.pathExists(
|
|
338
|
+
if (await fs.pathExists(path11.join(cwd, "yarn.lock"))) {
|
|
339
339
|
return "yarn";
|
|
340
340
|
}
|
|
341
|
-
if (await fs.pathExists(
|
|
341
|
+
if (await fs.pathExists(path11.join(cwd, "package-lock.json"))) {
|
|
342
342
|
return "npm";
|
|
343
343
|
}
|
|
344
344
|
try {
|
|
@@ -446,7 +446,7 @@ pnpm-debug.log*
|
|
|
446
446
|
.temp/
|
|
447
447
|
.tmp/
|
|
448
448
|
`;
|
|
449
|
-
await fs.writeFile(
|
|
449
|
+
await fs.writeFile(path11.join(cwd, ".gitignore"), gitignore);
|
|
450
450
|
}
|
|
451
451
|
async function createInitialCommit(cwd) {
|
|
452
452
|
await execa("git", ["add", "."], { cwd });
|
|
@@ -460,7 +460,7 @@ async function createCommand(projectName, options) {
|
|
|
460
460
|
if (!projectName) {
|
|
461
461
|
return exitWithCommandError("Project name is required");
|
|
462
462
|
}
|
|
463
|
-
const targetPath =
|
|
463
|
+
const targetPath = path11.join(process.cwd(), projectName);
|
|
464
464
|
if (!await isEmptyDir(targetPath)) {
|
|
465
465
|
return exitWithCommandError(`Directory ${projectName} already exists and is not empty`);
|
|
466
466
|
}
|
|
@@ -489,7 +489,7 @@ async function createCommand(projectName, options) {
|
|
|
489
489
|
});
|
|
490
490
|
logger.succeedSpinner("Template files copied");
|
|
491
491
|
logger.startSpinner("Updating package.json...");
|
|
492
|
-
const packageJsonPath =
|
|
492
|
+
const packageJsonPath = path11.join(targetPath, "package.json");
|
|
493
493
|
const packageJson = await readJson(packageJsonPath);
|
|
494
494
|
packageJson.name = answers.projectName;
|
|
495
495
|
if (answers.author) {
|
|
@@ -657,8 +657,8 @@ async function agentCreateCommand(name, options) {
|
|
|
657
657
|
logger.info(`Pattern: ${chalk4.cyan(answers.pattern)}`);
|
|
658
658
|
logger.newLine();
|
|
659
659
|
const cwd = process.cwd();
|
|
660
|
-
const agentDir =
|
|
661
|
-
const agentFile =
|
|
660
|
+
const agentDir = path11.join(cwd, "src", "agents");
|
|
661
|
+
const agentFile = path11.join(agentDir, `${answers.name}.ts`);
|
|
662
662
|
logger.startSpinner("Creating agent file...");
|
|
663
663
|
await ensureDir(agentDir);
|
|
664
664
|
const agentContent = generateAgentContent(answers.name, answers.pattern, answers.description);
|
|
@@ -666,8 +666,8 @@ async function agentCreateCommand(name, options) {
|
|
|
666
666
|
logger.succeedSpinner("Agent file created");
|
|
667
667
|
if (answers.generateTests) {
|
|
668
668
|
logger.startSpinner("Creating test file...");
|
|
669
|
-
const testDir =
|
|
670
|
-
const testFile =
|
|
669
|
+
const testDir = path11.join(cwd, "tests", "agents");
|
|
670
|
+
const testFile = path11.join(testDir, `${answers.name}.test.ts`);
|
|
671
671
|
await ensureDir(testDir);
|
|
672
672
|
const testContent = generateTestContent(answers.name, answers.pattern);
|
|
673
673
|
await writeFile(testFile, testContent);
|
|
@@ -825,7 +825,7 @@ async function agentCreateReusableCommand(name, options) {
|
|
|
825
825
|
logger.info(`Description: ${chalk4.gray(answers.description)}`);
|
|
826
826
|
logger.newLine();
|
|
827
827
|
const cwd = process.cwd();
|
|
828
|
-
const agentDir =
|
|
828
|
+
const agentDir = path11.join(cwd, answers.name);
|
|
829
829
|
const agentNameKebab = answers.name;
|
|
830
830
|
const agentNamePascal = kebabToPascal(agentNameKebab);
|
|
831
831
|
const agentNameCamel = kebabToCamel(agentNameKebab);
|
|
@@ -844,10 +844,10 @@ async function agentCreateReusableCommand(name, options) {
|
|
|
844
844
|
logger.succeedSpinner("Agent structure created");
|
|
845
845
|
logger.startSpinner("Organizing files...");
|
|
846
846
|
const fs5 = await import('fs-extra');
|
|
847
|
-
const srcDir =
|
|
847
|
+
const srcDir = path11.join(agentDir, "src");
|
|
848
848
|
await fs5.ensureDir(srcDir);
|
|
849
|
-
await fs5.move(
|
|
850
|
-
await fs5.move(
|
|
849
|
+
await fs5.move(path11.join(agentDir, "index.ts"), path11.join(srcDir, "index.ts"));
|
|
850
|
+
await fs5.move(path11.join(agentDir, "index.test.ts"), path11.join(srcDir, "index.test.ts"));
|
|
851
851
|
logger.succeedSpinner("Files organized");
|
|
852
852
|
logger.newLine();
|
|
853
853
|
logger.success(chalk4.bold.green("\u2728 Reusable agent created successfully!"));
|
|
@@ -879,7 +879,7 @@ async function agentListCommand(options) {
|
|
|
879
879
|
try {
|
|
880
880
|
logger.header("\u{1F4CB} List Agents");
|
|
881
881
|
const cwd = process.cwd();
|
|
882
|
-
const agentDir =
|
|
882
|
+
const agentDir = path11.join(cwd, "src", "agents");
|
|
883
883
|
const agentFiles = await findFiles("*.ts", agentDir);
|
|
884
884
|
if (agentFiles.length === 0) {
|
|
885
885
|
logger.warn("No agents found");
|
|
@@ -889,8 +889,8 @@ async function agentListCommand(options) {
|
|
|
889
889
|
logger.info(`Found ${chalk4.cyan(agentFiles.length)} agent(s):
|
|
890
890
|
`);
|
|
891
891
|
for (const file of agentFiles) {
|
|
892
|
-
const agentName =
|
|
893
|
-
const agentPath =
|
|
892
|
+
const agentName = path11.basename(file, ".ts");
|
|
893
|
+
const agentPath = path11.join(agentDir, file);
|
|
894
894
|
if (options.verbose) {
|
|
895
895
|
const content = await readFile(agentPath);
|
|
896
896
|
const pattern = extractPattern(content);
|
|
@@ -929,17 +929,17 @@ function extractDescription(content) {
|
|
|
929
929
|
const match = content.match(/\/\*\*\s*\n\s*\*\s*(.+?)\s*\n/);
|
|
930
930
|
return match ? match[1] : null;
|
|
931
931
|
}
|
|
932
|
-
async function
|
|
932
|
+
async function runNamedTestCommand(name, options, convention) {
|
|
933
933
|
try {
|
|
934
|
-
logger.header(
|
|
934
|
+
logger.header(`\u{1F9EA} Test ${convention.noun}`);
|
|
935
935
|
const cwd = process.cwd();
|
|
936
|
-
const testFile =
|
|
936
|
+
const testFile = path11.join(cwd, "tests", convention.testDirectory, `${name}.test.ts`);
|
|
937
937
|
if (!await pathExists(testFile)) {
|
|
938
938
|
logger.error(`Test file not found: ${testFile}`);
|
|
939
|
-
logger.info(`Create tests with: ${chalk4.cyan(
|
|
939
|
+
logger.info(`Create tests with: ${chalk4.cyan(convention.creationHint)}`);
|
|
940
940
|
return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
|
|
941
941
|
}
|
|
942
|
-
logger.info(`Testing
|
|
942
|
+
logger.info(`Testing ${convention.noun.toLowerCase()}: ${chalk4.cyan(name)}`);
|
|
943
943
|
logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
|
|
944
944
|
logger.newLine();
|
|
945
945
|
const packageManager = await detectPackageManager(cwd);
|
|
@@ -952,6 +952,15 @@ async function agentTestCommand(name, options) {
|
|
|
952
952
|
return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
|
|
953
953
|
}
|
|
954
954
|
}
|
|
955
|
+
|
|
956
|
+
// src/commands/agent/test.ts
|
|
957
|
+
async function agentTestCommand(name, options) {
|
|
958
|
+
return runNamedTestCommand(name, options, {
|
|
959
|
+
noun: "Agent",
|
|
960
|
+
testDirectory: "agents",
|
|
961
|
+
creationHint: `agentforge agent:create ${name} --test`
|
|
962
|
+
});
|
|
963
|
+
}
|
|
955
964
|
async function agentDeployCommand(name, options) {
|
|
956
965
|
try {
|
|
957
966
|
logger.header("\u{1F680} Deploy Agent");
|
|
@@ -1082,8 +1091,8 @@ function capitalize2(str) {
|
|
|
1082
1091
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
1083
1092
|
}
|
|
1084
1093
|
async function createSingleFileTool(cwd, answers) {
|
|
1085
|
-
const toolDir =
|
|
1086
|
-
const toolFile =
|
|
1094
|
+
const toolDir = path11.join(cwd, "src", "tools");
|
|
1095
|
+
const toolFile = path11.join(toolDir, `${answers.name}.ts`);
|
|
1087
1096
|
logger.startSpinner("Creating tool file...");
|
|
1088
1097
|
await ensureDir(toolDir);
|
|
1089
1098
|
const toolContent = generateToolContent(answers.name, answers.category, answers.description);
|
|
@@ -1091,8 +1100,8 @@ async function createSingleFileTool(cwd, answers) {
|
|
|
1091
1100
|
logger.succeedSpinner("Tool file created");
|
|
1092
1101
|
if (answers.generateTests) {
|
|
1093
1102
|
logger.startSpinner("Creating test file...");
|
|
1094
|
-
const testDir =
|
|
1095
|
-
const testFile =
|
|
1103
|
+
const testDir = path11.join(cwd, "tests", "tools");
|
|
1104
|
+
const testFile = path11.join(testDir, `${answers.name}.test.ts`);
|
|
1096
1105
|
await ensureDir(testDir);
|
|
1097
1106
|
const testContent = generateTestContent2(answers.name);
|
|
1098
1107
|
await writeFile(testFile, testContent);
|
|
@@ -1100,7 +1109,7 @@ async function createSingleFileTool(cwd, answers) {
|
|
|
1100
1109
|
}
|
|
1101
1110
|
}
|
|
1102
1111
|
async function createMultiFileTool(cwd, answers) {
|
|
1103
|
-
const toolDir =
|
|
1112
|
+
const toolDir = path11.join(cwd, "src", "tools", answers.name);
|
|
1104
1113
|
logger.startSpinner("Creating tool directory structure...");
|
|
1105
1114
|
await ensureDir(toolDir);
|
|
1106
1115
|
const templatePath = getTemplatePath("tool-multi");
|
|
@@ -1117,7 +1126,7 @@ async function createMultiFileTool(cwd, answers) {
|
|
|
1117
1126
|
if (!answers.generateTests) {
|
|
1118
1127
|
logger.startSpinner("Cleaning up test files...");
|
|
1119
1128
|
const fs5 = await import('fs-extra');
|
|
1120
|
-
const testDir =
|
|
1129
|
+
const testDir = path11.join(toolDir, "__tests__");
|
|
1121
1130
|
await fs5.remove(testDir);
|
|
1122
1131
|
logger.succeedSpinner("Test files removed");
|
|
1123
1132
|
}
|
|
@@ -1126,7 +1135,7 @@ async function toolListCommand(options) {
|
|
|
1126
1135
|
try {
|
|
1127
1136
|
logger.header("\u{1F4CB} List Tools");
|
|
1128
1137
|
const cwd = process.cwd();
|
|
1129
|
-
const toolDir =
|
|
1138
|
+
const toolDir = path11.join(cwd, "src", "tools");
|
|
1130
1139
|
const toolFiles = await findFiles("*.ts", toolDir);
|
|
1131
1140
|
if (toolFiles.length === 0) {
|
|
1132
1141
|
logger.warn("No tools found");
|
|
@@ -1137,7 +1146,7 @@ async function toolListCommand(options) {
|
|
|
1137
1146
|
if (options.category) {
|
|
1138
1147
|
filteredTools = [];
|
|
1139
1148
|
for (const file of toolFiles) {
|
|
1140
|
-
const toolPath =
|
|
1149
|
+
const toolPath = path11.join(toolDir, file);
|
|
1141
1150
|
const content = await readFile(toolPath);
|
|
1142
1151
|
const category = extractCategory(content);
|
|
1143
1152
|
if (category === options.category) {
|
|
@@ -1152,8 +1161,8 @@ async function toolListCommand(options) {
|
|
|
1152
1161
|
logger.info(`Found ${chalk4.cyan(filteredTools.length)} tool(s):
|
|
1153
1162
|
`);
|
|
1154
1163
|
for (const file of filteredTools) {
|
|
1155
|
-
const toolName =
|
|
1156
|
-
const toolPath =
|
|
1164
|
+
const toolName = path11.basename(file, ".ts");
|
|
1165
|
+
const toolPath = path11.join(toolDir, file);
|
|
1157
1166
|
if (options.verbose) {
|
|
1158
1167
|
const content = await readFile(toolPath);
|
|
1159
1168
|
const category = extractCategory(content);
|
|
@@ -1187,38 +1196,24 @@ function extractDescription2(content) {
|
|
|
1187
1196
|
const match = content.match(/\/\*\*\s*\n\s*\*\s*(.+?)\s*\n/);
|
|
1188
1197
|
return match ? match[1] : null;
|
|
1189
1198
|
}
|
|
1199
|
+
|
|
1200
|
+
// src/commands/tool/test.ts
|
|
1190
1201
|
async function toolTestCommand(name, options) {
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
logger.error(`Test file not found: ${testFile}`);
|
|
1197
|
-
logger.info(`Create tests with: ${chalk4.cyan(`agentforge tool:create ${name} --test`)}`);
|
|
1198
|
-
return exitWithCommandError(`Test file not found: ${testFile}`, { logError: false });
|
|
1199
|
-
}
|
|
1200
|
-
logger.info(`Testing tool: ${chalk4.cyan(name)}`);
|
|
1201
|
-
logger.info(`Watch mode: ${options.watch ? "Yes" : "No"}`);
|
|
1202
|
-
logger.newLine();
|
|
1203
|
-
const packageManager = await detectPackageManager(cwd);
|
|
1204
|
-
logger.startSpinner("Running tests...");
|
|
1205
|
-
const testCommand2 = options.watch ? "test:watch" : "test";
|
|
1206
|
-
process.env.TEST_FILE = testFile;
|
|
1207
|
-
await runScript(cwd, testCommand2, packageManager);
|
|
1208
|
-
logger.succeedSpinner("Tests completed");
|
|
1209
|
-
} catch (error) {
|
|
1210
|
-
return exitWithCommandError(error, { spinnerFailureText: "Tests failed" });
|
|
1211
|
-
}
|
|
1202
|
+
return runNamedTestCommand(name, options, {
|
|
1203
|
+
noun: "Tool",
|
|
1204
|
+
testDirectory: "tools",
|
|
1205
|
+
creationHint: `agentforge tool:create ${name} --test`
|
|
1206
|
+
});
|
|
1212
1207
|
}
|
|
1213
1208
|
async function resolveToolPath(name) {
|
|
1214
1209
|
const cwd = process.cwd();
|
|
1215
1210
|
const isScopedPackage = /^@[^/]+\/[^/]+$/.test(name);
|
|
1216
1211
|
const isPath = !isScopedPackage && (name.includes("/") || name.includes("\\"));
|
|
1217
1212
|
if (isPath) {
|
|
1218
|
-
const absolutePath =
|
|
1213
|
+
const absolutePath = path11.isAbsolute(name) ? name : path11.resolve(cwd, name);
|
|
1219
1214
|
return validateToolPath(absolutePath, name);
|
|
1220
1215
|
}
|
|
1221
|
-
const cwdPackageJsonPath =
|
|
1216
|
+
const cwdPackageJsonPath = path11.join(cwd, "package.json");
|
|
1222
1217
|
if (await fs.pathExists(cwdPackageJsonPath)) {
|
|
1223
1218
|
const cwdPackageJson = await fs.readJson(cwdPackageJsonPath);
|
|
1224
1219
|
if (cwdPackageJson.name === name || cwdPackageJson.name === `@agentforge/${name}`) {
|
|
@@ -1228,7 +1223,7 @@ async function resolveToolPath(name) {
|
|
|
1228
1223
|
const possiblePaths = buildPossiblePaths(cwd, name, isScopedPackage);
|
|
1229
1224
|
for (const possiblePath of possiblePaths) {
|
|
1230
1225
|
if (await fs.pathExists(possiblePath)) {
|
|
1231
|
-
const packageJsonPath =
|
|
1226
|
+
const packageJsonPath = path11.join(possiblePath, "package.json");
|
|
1232
1227
|
if (await fs.pathExists(packageJsonPath)) {
|
|
1233
1228
|
return validateToolPath(possiblePath, name);
|
|
1234
1229
|
}
|
|
@@ -1239,7 +1234,7 @@ async function resolveToolPath(name) {
|
|
|
1239
1234
|
logger.info("Tried the following locations:");
|
|
1240
1235
|
logger.list([
|
|
1241
1236
|
`Current directory (${cwd})`,
|
|
1242
|
-
...possiblePaths.map((possiblePath) =>
|
|
1237
|
+
...possiblePaths.map((possiblePath) => path11.relative(cwd, possiblePath) || ".")
|
|
1243
1238
|
]);
|
|
1244
1239
|
logger.newLine();
|
|
1245
1240
|
logger.info("Make sure you are either:");
|
|
@@ -1252,16 +1247,16 @@ async function resolveToolPath(name) {
|
|
|
1252
1247
|
}
|
|
1253
1248
|
function buildPossiblePaths(cwd, name, isScopedPackage) {
|
|
1254
1249
|
const possiblePaths = [
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1250
|
+
path11.join(cwd, "tools", name),
|
|
1251
|
+
path11.join(cwd, "packages", name),
|
|
1252
|
+
path11.join(cwd, name)
|
|
1258
1253
|
];
|
|
1259
1254
|
if (isScopedPackage) {
|
|
1260
1255
|
const unscopedName = name.split("/")[1];
|
|
1261
1256
|
possiblePaths.push(
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1257
|
+
path11.join(cwd, "tools", unscopedName),
|
|
1258
|
+
path11.join(cwd, "packages", unscopedName),
|
|
1259
|
+
path11.join(cwd, unscopedName)
|
|
1265
1260
|
);
|
|
1266
1261
|
}
|
|
1267
1262
|
return possiblePaths;
|
|
@@ -1270,7 +1265,7 @@ async function validateToolPath(toolPath, expectedName) {
|
|
|
1270
1265
|
if (!await fs.pathExists(toolPath)) {
|
|
1271
1266
|
return exitWithCommandError(`Tool directory not found: ${toolPath}`);
|
|
1272
1267
|
}
|
|
1273
|
-
const packageJsonPath =
|
|
1268
|
+
const packageJsonPath = path11.join(toolPath, "package.json");
|
|
1274
1269
|
if (!await fs.pathExists(packageJsonPath)) {
|
|
1275
1270
|
logger.info("Tool packages must have a package.json file");
|
|
1276
1271
|
return exitWithCommandError(`package.json not found in: ${toolPath}`);
|