@agentforge/cli 0.11.5 → 0.11.6

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 CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  var commander = require('commander');
4
4
  var chalk4 = require('chalk');
5
- var path6 = require('path');
5
+ var path12 = require('path');
6
6
  var ora = require('ora');
7
7
  var inquirer = require('inquirer');
8
8
  var fs = require('fs-extra');
@@ -14,7 +14,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
14
14
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
15
15
 
16
16
  var chalk4__default = /*#__PURE__*/_interopDefault(chalk4);
17
- var path6__default = /*#__PURE__*/_interopDefault(path6);
17
+ var path12__default = /*#__PURE__*/_interopDefault(path12);
18
18
  var ora__default = /*#__PURE__*/_interopDefault(ora);
19
19
  var inquirer__default = /*#__PURE__*/_interopDefault(inquirer);
20
20
  var fs__default = /*#__PURE__*/_interopDefault(fs);
@@ -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 = path6__default.default.dirname(__filename$1);
264
+ var __dirname$1 = path12__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 = 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));
282
+ const sourcePath = path12__default.default.join(templatePath, file);
283
+ const destPath = path12__default.default.join(targetPath, file);
284
+ await fs__default.default.ensureDir(path12__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(path6__default.default.dirname(filePath));
308
+ await fs__default.default.ensureDir(path12__default.default.dirname(filePath));
309
309
  await fs__default.default.writeFile(filePath, content);
310
310
  }
311
311
  function getTemplatePath(template) {
312
- return path6__default.default.join(__dirname$1, "..", "templates", template);
312
+ return path12__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(path6__default.default.join(cwd, "pnpm-lock.yaml"))) {
322
+ if (await fs__default.default.pathExists(path12__default.default.join(cwd, "pnpm-lock.yaml"))) {
323
323
  return "pnpm";
324
324
  }
325
- if (await fs__default.default.pathExists(path6__default.default.join(cwd, "yarn.lock"))) {
325
+ if (await fs__default.default.pathExists(path12__default.default.join(cwd, "yarn.lock"))) {
326
326
  return "yarn";
327
327
  }
328
- if (await fs__default.default.pathExists(path6__default.default.join(cwd, "package-lock.json"))) {
328
+ if (await fs__default.default.pathExists(path12__default.default.join(cwd, "package-lock.json"))) {
329
329
  return "npm";
330
330
  }
331
331
  try {
@@ -433,7 +433,7 @@ pnpm-debug.log*
433
433
  .temp/
434
434
  .tmp/
435
435
  `;
436
- await fs__default.default.writeFile(path6__default.default.join(cwd, ".gitignore"), gitignore);
436
+ await fs__default.default.writeFile(path12__default.default.join(cwd, ".gitignore"), gitignore);
437
437
  }
438
438
  async function createInitialCommit(cwd) {
439
439
  await execa.execa("git", ["add", "."], { cwd });
@@ -448,7 +448,7 @@ async function createCommand(projectName, options) {
448
448
  logger.error("Project name is required");
449
449
  process.exit(1);
450
450
  }
451
- const targetPath = path6__default.default.join(process.cwd(), projectName);
451
+ const targetPath = path12__default.default.join(process.cwd(), projectName);
452
452
  if (!await isEmptyDir(targetPath)) {
453
453
  logger.error(`Directory ${projectName} already exists and is not empty`);
454
454
  process.exit(1);
@@ -478,7 +478,7 @@ async function createCommand(projectName, options) {
478
478
  });
479
479
  logger.succeedSpinner("Template files copied");
480
480
  logger.startSpinner("Updating package.json...");
481
- const packageJsonPath = path6__default.default.join(targetPath, "package.json");
481
+ const packageJsonPath = path12__default.default.join(targetPath, "package.json");
482
482
  const packageJson = await readJson(packageJsonPath);
483
483
  packageJson.name = answers.projectName;
484
484
  if (answers.author) {
@@ -652,8 +652,8 @@ async function agentCreateCommand(name, options) {
652
652
  logger.info(`Pattern: ${chalk4__default.default.cyan(answers.pattern)}`);
653
653
  logger.newLine();
654
654
  const cwd = process.cwd();
655
- const agentDir = path6__default.default.join(cwd, "src", "agents");
656
- const agentFile = path6__default.default.join(agentDir, `${answers.name}.ts`);
655
+ const agentDir = path12__default.default.join(cwd, "src", "agents");
656
+ const agentFile = path12__default.default.join(agentDir, `${answers.name}.ts`);
657
657
  logger.startSpinner("Creating agent file...");
658
658
  await ensureDir(agentDir);
659
659
  const agentContent = generateAgentContent(answers.name, answers.pattern, answers.description);
@@ -661,8 +661,8 @@ async function agentCreateCommand(name, options) {
661
661
  logger.succeedSpinner("Agent file created");
662
662
  if (answers.generateTests) {
663
663
  logger.startSpinner("Creating test file...");
664
- const testDir = path6__default.default.join(cwd, "tests", "agents");
665
- const testFile = path6__default.default.join(testDir, `${answers.name}.test.ts`);
664
+ const testDir = path12__default.default.join(cwd, "tests", "agents");
665
+ const testFile = path12__default.default.join(testDir, `${answers.name}.test.ts`);
666
666
  await ensureDir(testDir);
667
667
  const testContent = generateTestContent(answers.name, answers.pattern);
668
668
  await writeFile(testFile, testContent);
@@ -821,7 +821,7 @@ async function agentCreateReusableCommand(name, options) {
821
821
  logger.info(`Description: ${chalk4__default.default.gray(answers.description)}`);
822
822
  logger.newLine();
823
823
  const cwd = process.cwd();
824
- const agentDir = path6__default.default.join(cwd, answers.name);
824
+ const agentDir = path12__default.default.join(cwd, answers.name);
825
825
  const agentNameKebab = answers.name;
826
826
  const agentNamePascal = kebabToPascal(agentNameKebab);
827
827
  const agentNameCamel = kebabToCamel(agentNameKebab);
@@ -839,12 +839,12 @@ async function agentCreateReusableCommand(name, options) {
839
839
  await copyTemplate(templatePath, agentDir, replacements);
840
840
  logger.succeedSpinner("Agent structure created");
841
841
  logger.startSpinner("Organizing files...");
842
- const fs4 = await import('fs-extra');
843
- const srcDir = path6__default.default.join(agentDir, "src");
844
- await fs4.ensureDir(srcDir);
845
- await fs4.move(path6__default.default.join(agentDir, "index.ts"), path6__default.default.join(srcDir, "index.ts"));
846
- await fs4.move(path6__default.default.join(agentDir, "prompt-loader.ts"), path6__default.default.join(srcDir, "prompt-loader.ts"));
847
- await fs4.move(path6__default.default.join(agentDir, "index.test.ts"), path6__default.default.join(srcDir, "index.test.ts"));
842
+ const fs5 = await import('fs-extra');
843
+ const srcDir = path12__default.default.join(agentDir, "src");
844
+ await fs5.ensureDir(srcDir);
845
+ await fs5.move(path12__default.default.join(agentDir, "index.ts"), path12__default.default.join(srcDir, "index.ts"));
846
+ await fs5.move(path12__default.default.join(agentDir, "prompt-loader.ts"), path12__default.default.join(srcDir, "prompt-loader.ts"));
847
+ await fs5.move(path12__default.default.join(agentDir, "index.test.ts"), path12__default.default.join(srcDir, "index.test.ts"));
848
848
  logger.succeedSpinner("Files organized");
849
849
  logger.newLine();
850
850
  logger.success(chalk4__default.default.bold.green("\u2728 Reusable agent created successfully!"));
@@ -877,7 +877,7 @@ async function agentListCommand(options) {
877
877
  try {
878
878
  logger.header("\u{1F4CB} List Agents");
879
879
  const cwd = process.cwd();
880
- const agentDir = path6__default.default.join(cwd, "src", "agents");
880
+ const agentDir = path12__default.default.join(cwd, "src", "agents");
881
881
  const agentFiles = await findFiles("*.ts", agentDir);
882
882
  if (agentFiles.length === 0) {
883
883
  logger.warn("No agents found");
@@ -887,8 +887,8 @@ async function agentListCommand(options) {
887
887
  logger.info(`Found ${chalk4__default.default.cyan(agentFiles.length)} agent(s):
888
888
  `);
889
889
  for (const file of agentFiles) {
890
- const agentName = path6__default.default.basename(file, ".ts");
891
- const agentPath = path6__default.default.join(agentDir, file);
890
+ const agentName = path12__default.default.basename(file, ".ts");
891
+ const agentPath = path12__default.default.join(agentDir, file);
892
892
  if (options.verbose) {
893
893
  const content = await readFile(agentPath);
894
894
  const pattern = extractPattern(content);
@@ -932,7 +932,7 @@ async function agentTestCommand(name, options) {
932
932
  try {
933
933
  logger.header("\u{1F9EA} Test Agent");
934
934
  const cwd = process.cwd();
935
- const testFile = path6__default.default.join(cwd, "tests", "agents", `${name}.test.ts`);
935
+ const testFile = path12__default.default.join(cwd, "tests", "agents", `${name}.test.ts`);
936
936
  if (!await pathExists(testFile)) {
937
937
  logger.error(`Test file not found: ${testFile}`);
938
938
  logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge agent:create ${name} --test`)}`);
@@ -1083,8 +1083,8 @@ function capitalize2(str) {
1083
1083
  return str.charAt(0).toUpperCase() + str.slice(1);
1084
1084
  }
1085
1085
  async function createSingleFileTool(cwd, answers) {
1086
- const toolDir = path6__default.default.join(cwd, "src", "tools");
1087
- const toolFile = path6__default.default.join(toolDir, `${answers.name}.ts`);
1086
+ const toolDir = path12__default.default.join(cwd, "src", "tools");
1087
+ const toolFile = path12__default.default.join(toolDir, `${answers.name}.ts`);
1088
1088
  logger.startSpinner("Creating tool file...");
1089
1089
  await ensureDir(toolDir);
1090
1090
  const toolContent = generateToolContent(answers.name, answers.category, answers.description);
@@ -1092,8 +1092,8 @@ async function createSingleFileTool(cwd, answers) {
1092
1092
  logger.succeedSpinner("Tool file created");
1093
1093
  if (answers.generateTests) {
1094
1094
  logger.startSpinner("Creating test file...");
1095
- const testDir = path6__default.default.join(cwd, "tests", "tools");
1096
- const testFile = path6__default.default.join(testDir, `${answers.name}.test.ts`);
1095
+ const testDir = path12__default.default.join(cwd, "tests", "tools");
1096
+ const testFile = path12__default.default.join(testDir, `${answers.name}.test.ts`);
1097
1097
  await ensureDir(testDir);
1098
1098
  const testContent = generateTestContent2(answers.name);
1099
1099
  await writeFile(testFile, testContent);
@@ -1101,7 +1101,7 @@ async function createSingleFileTool(cwd, answers) {
1101
1101
  }
1102
1102
  }
1103
1103
  async function createMultiFileTool(cwd, answers) {
1104
- const toolDir = path6__default.default.join(cwd, "src", "tools", answers.name);
1104
+ const toolDir = path12__default.default.join(cwd, "src", "tools", answers.name);
1105
1105
  logger.startSpinner("Creating tool directory structure...");
1106
1106
  await ensureDir(toolDir);
1107
1107
  const templatePath = getTemplatePath("tool-multi");
@@ -1116,9 +1116,9 @@ async function createMultiFileTool(cwd, answers) {
1116
1116
  logger.succeedSpinner("Tool directory structure created");
1117
1117
  if (!answers.generateTests) {
1118
1118
  logger.startSpinner("Cleaning up test files...");
1119
- const fs4 = await import('fs-extra');
1120
- const testDir = path6__default.default.join(toolDir, "__tests__");
1121
- await fs4.remove(testDir);
1119
+ const fs5 = await import('fs-extra');
1120
+ const testDir = path12__default.default.join(toolDir, "__tests__");
1121
+ await fs5.remove(testDir);
1122
1122
  logger.succeedSpinner("Test files removed");
1123
1123
  }
1124
1124
  }
@@ -1126,7 +1126,7 @@ async function toolListCommand(options) {
1126
1126
  try {
1127
1127
  logger.header("\u{1F4CB} List Tools");
1128
1128
  const cwd = process.cwd();
1129
- const toolDir = path6__default.default.join(cwd, "src", "tools");
1129
+ const toolDir = path12__default.default.join(cwd, "src", "tools");
1130
1130
  const toolFiles = await findFiles("*.ts", toolDir);
1131
1131
  if (toolFiles.length === 0) {
1132
1132
  logger.warn("No tools found");
@@ -1137,7 +1137,7 @@ async function toolListCommand(options) {
1137
1137
  if (options.category) {
1138
1138
  filteredTools = [];
1139
1139
  for (const file of toolFiles) {
1140
- const toolPath = path6__default.default.join(toolDir, file);
1140
+ const toolPath = path12__default.default.join(toolDir, file);
1141
1141
  const content = await readFile(toolPath);
1142
1142
  const category = extractCategory(content);
1143
1143
  if (category === options.category) {
@@ -1152,8 +1152,8 @@ async function toolListCommand(options) {
1152
1152
  logger.info(`Found ${chalk4__default.default.cyan(filteredTools.length)} tool(s):
1153
1153
  `);
1154
1154
  for (const file of filteredTools) {
1155
- const toolName = path6__default.default.basename(file, ".ts");
1156
- const toolPath = path6__default.default.join(toolDir, file);
1155
+ const toolName = path12__default.default.basename(file, ".ts");
1156
+ const toolPath = path12__default.default.join(toolDir, file);
1157
1157
  if (options.verbose) {
1158
1158
  const content = await readFile(toolPath);
1159
1159
  const category = extractCategory(content);
@@ -1192,7 +1192,7 @@ async function toolTestCommand(name, options) {
1192
1192
  try {
1193
1193
  logger.header("\u{1F9EA} Test Tool");
1194
1194
  const cwd = process.cwd();
1195
- const testFile = path6__default.default.join(cwd, "tests", "tools", `${name}.test.ts`);
1195
+ const testFile = path12__default.default.join(cwd, "tests", "tools", `${name}.test.ts`);
1196
1196
  if (!await pathExists(testFile)) {
1197
1197
  logger.error(`Test file not found: ${testFile}`);
1198
1198
  logger.info(`Create tests with: ${chalk4__default.default.cyan(`agentforge tool:create ${name} --test`)}`);
@@ -1224,28 +1224,36 @@ async function toolPublishCommand(name, options) {
1224
1224
  logger.warn("Dry run mode - no actual publishing will occur");
1225
1225
  logger.newLine();
1226
1226
  }
1227
- const cwd = process.cwd();
1228
- const packageManager = await detectPackageManager(cwd);
1229
- logger.startSpinner("Running tests...");
1230
- try {
1231
- await runScript(cwd, "test", packageManager);
1232
- logger.succeedSpinner("Tests passed");
1233
- } catch (error) {
1234
- logger.failSpinner("Tests failed");
1235
- logger.error("Cannot publish tool with failing tests");
1236
- process.exit(1);
1227
+ const { toolPath, hasTestScript, hasBuildScript } = await resolveToolPath(name);
1228
+ const packageManager = await detectPackageManager(toolPath);
1229
+ if (hasTestScript) {
1230
+ logger.startSpinner("Running tests...");
1231
+ try {
1232
+ await runScript(toolPath, "test", packageManager);
1233
+ logger.succeedSpinner("Tests passed");
1234
+ } catch (error) {
1235
+ logger.failSpinner("Tests failed");
1236
+ logger.error("Cannot publish tool with failing tests");
1237
+ process.exit(1);
1238
+ }
1239
+ } else {
1240
+ logger.info("\u26A0\uFE0F Skipping tests (no test script found)");
1237
1241
  }
1238
- logger.startSpinner("Building tool...");
1239
- try {
1240
- await runScript(cwd, "build", packageManager);
1241
- logger.succeedSpinner("Build completed");
1242
- } catch (error) {
1243
- logger.failSpinner("Build failed");
1244
- process.exit(1);
1242
+ if (hasBuildScript) {
1243
+ logger.startSpinner("Building tool...");
1244
+ try {
1245
+ await runScript(toolPath, "build", packageManager);
1246
+ logger.succeedSpinner("Build completed");
1247
+ } catch (error) {
1248
+ logger.failSpinner("Build failed");
1249
+ process.exit(1);
1250
+ }
1251
+ } else {
1252
+ logger.info("\u26A0\uFE0F Skipping build (no build script found)");
1245
1253
  }
1246
1254
  logger.startSpinner(options.dryRun ? "Running dry-run publish..." : "Publishing to npm...");
1247
1255
  try {
1248
- await publishPackage(cwd, {
1256
+ await publishPackage(toolPath, {
1249
1257
  tag: options.tag,
1250
1258
  access: "public",
1251
1259
  dryRun: options.dryRun
@@ -1288,6 +1296,95 @@ async function toolPublishCommand(name, options) {
1288
1296
  process.exit(1);
1289
1297
  }
1290
1298
  }
1299
+ async function resolveToolPath(name) {
1300
+ const cwd = process.cwd();
1301
+ const isScopedPackage = /^@[^/]+\/[^/]+$/.test(name);
1302
+ const isPath = !isScopedPackage && (name.includes("/") || name.includes("\\"));
1303
+ if (isPath) {
1304
+ const absolutePath = path12__default.default.isAbsolute(name) ? name : path12__default.default.resolve(cwd, name);
1305
+ return await validateToolPath(absolutePath, name);
1306
+ }
1307
+ const cwdPackageJsonPath = path12__default.default.join(cwd, "package.json");
1308
+ if (await fs__default.default.pathExists(cwdPackageJsonPath)) {
1309
+ const cwdPackageJson = await fs__default.default.readJson(cwdPackageJsonPath);
1310
+ if (cwdPackageJson.name === name || cwdPackageJson.name === `@agentforge/${name}`) {
1311
+ return await validateToolPath(cwd, name);
1312
+ }
1313
+ }
1314
+ const unscopedName = isScopedPackage ? name.split("/")[1] : name;
1315
+ const possiblePaths = [
1316
+ path12__default.default.join(cwd, "tools", name),
1317
+ path12__default.default.join(cwd, "packages", name),
1318
+ path12__default.default.join(cwd, name)
1319
+ ];
1320
+ if (isScopedPackage) {
1321
+ possiblePaths.push(
1322
+ path12__default.default.join(cwd, "tools", unscopedName),
1323
+ path12__default.default.join(cwd, "packages", unscopedName),
1324
+ path12__default.default.join(cwd, unscopedName)
1325
+ );
1326
+ }
1327
+ for (const possiblePath of possiblePaths) {
1328
+ if (await fs__default.default.pathExists(possiblePath)) {
1329
+ const packageJsonPath = path12__default.default.join(possiblePath, "package.json");
1330
+ if (await fs__default.default.pathExists(packageJsonPath)) {
1331
+ return await validateToolPath(possiblePath, name);
1332
+ }
1333
+ }
1334
+ }
1335
+ logger.error(`Could not find tool package: ${chalk4__default.default.cyan(name)}`);
1336
+ logger.newLine();
1337
+ logger.info("Tried the following locations:");
1338
+ logger.list([
1339
+ `Current directory (${cwd})`,
1340
+ ...possiblePaths.map((p) => path12__default.default.relative(cwd, p) || ".")
1341
+ ]);
1342
+ logger.newLine();
1343
+ logger.info("Make sure you are either:");
1344
+ logger.list([
1345
+ "In the tool package directory with matching package.json name",
1346
+ "Providing a path to the tool package directory",
1347
+ "Have the tool in a standard location (./tools/<name>, ./packages/<name>)"
1348
+ ]);
1349
+ process.exit(1);
1350
+ }
1351
+ async function validateToolPath(toolPath, expectedName) {
1352
+ if (!await fs__default.default.pathExists(toolPath)) {
1353
+ logger.error(`Tool directory not found: ${toolPath}`);
1354
+ process.exit(1);
1355
+ }
1356
+ const packageJsonPath = path12__default.default.join(toolPath, "package.json");
1357
+ if (!await fs__default.default.pathExists(packageJsonPath)) {
1358
+ logger.error(`package.json not found in: ${toolPath}`);
1359
+ logger.info("Tool packages must have a package.json file");
1360
+ process.exit(1);
1361
+ }
1362
+ let packageJson;
1363
+ try {
1364
+ packageJson = await fs__default.default.readJson(packageJsonPath);
1365
+ } catch (error) {
1366
+ logger.error(`Failed to read package.json: ${error.message}`);
1367
+ process.exit(1);
1368
+ }
1369
+ if (!packageJson.name) {
1370
+ logger.error('package.json must have a "name" field');
1371
+ process.exit(1);
1372
+ }
1373
+ const packageName = packageJson.name;
1374
+ const nameMatches = packageName === expectedName || packageName === `@agentforge/${expectedName}` || packageName.endsWith(`/${expectedName}`);
1375
+ if (!nameMatches) {
1376
+ logger.warn(`Package name mismatch: expected ${chalk4__default.default.cyan(expectedName)}, found ${chalk4__default.default.cyan(packageName)}`);
1377
+ logger.info(`Publishing package: ${chalk4__default.default.cyan(packageName)}`);
1378
+ logger.newLine();
1379
+ }
1380
+ const hasTestScript = !!packageJson.scripts?.test;
1381
+ const hasBuildScript = !!packageJson.scripts?.build;
1382
+ return {
1383
+ toolPath,
1384
+ hasTestScript,
1385
+ hasBuildScript
1386
+ };
1387
+ }
1291
1388
 
1292
1389
  // src/index.ts
1293
1390
  var program = new commander.Command();