Merge commit '0ccb161774e2b6238173388abe7f7f696b2f481f'
This commit is contained in:
@@ -298,3 +298,53 @@ module.exports = {
|
|||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const agentName = process.argv[2];
|
||||||
|
|
||||||
|
if (!agentName) {
|
||||||
|
console.error("❌ Please provide an agent name: `npm run spawn-agent <agent-name>`");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const toTitleCase = (str) => str.replace(/-/g, " ").replace(/\b\w/g, c => c.toUpperCase());
|
||||||
|
|
||||||
|
const agentId = agentName.toLowerCase().replace(/\s+/g, "-");
|
||||||
|
const displayName = toTitleCase(agentId);
|
||||||
|
|
||||||
|
const output = {
|
||||||
|
id: agentId,
|
||||||
|
name: displayName,
|
||||||
|
role: "worker",
|
||||||
|
traits: ["emoji-native"],
|
||||||
|
inputs: [],
|
||||||
|
outputs: [],
|
||||||
|
description: `This is the ${displayName} agent.`,
|
||||||
|
triggers: [],
|
||||||
|
inherits_from: "base-agent"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Paths
|
||||||
|
const jsonPath = `agents/${agentId}.agent.json`;
|
||||||
|
const promptPath = `agents/${agentId}.prompt.txt`;
|
||||||
|
const workflowPath = `.github/workflows/${agentId}.workflow.yml`;
|
||||||
|
const docPath = `docs/agents/${agentId}.mdx`;
|
||||||
|
|
||||||
|
// Files
|
||||||
|
fs.mkdirSync("agents", { recursive: true });
|
||||||
|
fs.writeFileSync(jsonPath, JSON.stringify(output, null, 2));
|
||||||
|
|
||||||
|
fs.writeFileSync(promptPath, `SYSTEM:\nYou are the ${displayName} agent. Your job is to...`);
|
||||||
|
|
||||||
|
fs.mkdirSync(".github/workflows", { recursive: true });
|
||||||
|
fs.writeFileSync(workflowPath, `name: ${displayName} Workflow\non:\n workflow_dispatch:\njobs:\n run:\n runs-on: ubuntu-latest\n steps:\n - run: echo "${displayName} agent triggered!"`);
|
||||||
|
|
||||||
|
fs.mkdirSync("docs/agents", { recursive: true });
|
||||||
|
fs.writeFileSync(docPath, `# ${displayName} Agent\n\nAuto-generated.\n\n## Purpose\nTBD`);
|
||||||
|
|
||||||
|
console.log(`✅ Created agent: ${agentId}`);
|
||||||
|
console.log(`├─ ${jsonPath}`);
|
||||||
|
console.log(`├─ ${promptPath}`);
|
||||||
|
console.log(`├─ ${workflowPath}`);
|
||||||
|
console.log(`└─ ${docPath}`);
|
||||||
|
|||||||
@@ -13,6 +13,27 @@ describe("spawn-agent", () => {
|
|||||||
// Create test output directory
|
// Create test output directory
|
||||||
if (!fs.existsSync(TEST_OUTPUT_DIR)) {
|
if (!fs.existsSync(TEST_OUTPUT_DIR)) {
|
||||||
fs.mkdirSync(TEST_OUTPUT_DIR, { recursive: true });
|
fs.mkdirSync(TEST_OUTPUT_DIR, { recursive: true });
|
||||||
|
import { describe, expect, it, beforeEach, afterEach } from "vitest";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
|
const TEST_AGENT_NAME = "test-agent-xyz";
|
||||||
|
const ROOT_DIR = path.join(__dirname, "..");
|
||||||
|
|
||||||
|
describe("spawn-agent.js", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
// Clean up any existing test agent files before each test
|
||||||
|
const paths = [
|
||||||
|
path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.agent.json`),
|
||||||
|
path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.prompt.txt`),
|
||||||
|
path.join(ROOT_DIR, ".github", "workflows", `${TEST_AGENT_NAME}.workflow.yml`),
|
||||||
|
path.join(ROOT_DIR, "docs", "agents", `${TEST_AGENT_NAME}.mdx`),
|
||||||
|
];
|
||||||
|
for (const p of paths) {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
fs.unlinkSync(p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -195,5 +216,107 @@ describe("AgentRegistry", () => {
|
|||||||
|
|
||||||
expect(ids.length).toBeGreaterThan(0);
|
expect(ids.length).toBeGreaterThan(0);
|
||||||
expect(ids).toContain("scribe-agent");
|
expect(ids).toContain("scribe-agent");
|
||||||
|
// Clean up test agent files after each test
|
||||||
|
const paths = [
|
||||||
|
path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.agent.json`),
|
||||||
|
path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.prompt.txt`),
|
||||||
|
path.join(ROOT_DIR, ".github", "workflows", `${TEST_AGENT_NAME}.workflow.yml`),
|
||||||
|
path.join(ROOT_DIR, "docs", "agents", `${TEST_AGENT_NAME}.mdx`),
|
||||||
|
];
|
||||||
|
for (const p of paths) {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
fs.unlinkSync(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Clean up directories if empty
|
||||||
|
const dirs = [
|
||||||
|
path.join(ROOT_DIR, "agents"),
|
||||||
|
path.join(ROOT_DIR, "docs", "agents"),
|
||||||
|
];
|
||||||
|
for (const d of dirs) {
|
||||||
|
if (fs.existsSync(d) && fs.readdirSync(d).length === 0) {
|
||||||
|
fs.rmSync(d, { recursive: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should show error when no agent name provided", () => {
|
||||||
|
let error: Error | null = null;
|
||||||
|
try {
|
||||||
|
execSync("node scripts/spawn-agent.js", { cwd: ROOT_DIR, encoding: "utf-8" });
|
||||||
|
} catch (e: any) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
expect(error).not.toBeNull();
|
||||||
|
expect(error!.message).toContain("Please provide an agent name");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create all required files when agent name provided", () => {
|
||||||
|
const output = execSync(`node scripts/spawn-agent.js ${TEST_AGENT_NAME}`, {
|
||||||
|
cwd: ROOT_DIR,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(output).toContain(`Created agent: ${TEST_AGENT_NAME}`);
|
||||||
|
|
||||||
|
// Check agent JSON file
|
||||||
|
const jsonPath = path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.agent.json`);
|
||||||
|
expect(fs.existsSync(jsonPath)).toBe(true);
|
||||||
|
const jsonContent = JSON.parse(fs.readFileSync(jsonPath, "utf-8"));
|
||||||
|
expect(jsonContent.id).toBe(TEST_AGENT_NAME);
|
||||||
|
expect(jsonContent.name).toBe("Test Agent Xyz");
|
||||||
|
expect(jsonContent.role).toBe("worker");
|
||||||
|
expect(jsonContent.traits).toContain("emoji-native");
|
||||||
|
expect(jsonContent.inherits_from).toBe("base-agent");
|
||||||
|
|
||||||
|
// Check prompt file
|
||||||
|
const promptPath = path.join(ROOT_DIR, "agents", `${TEST_AGENT_NAME}.prompt.txt`);
|
||||||
|
expect(fs.existsSync(promptPath)).toBe(true);
|
||||||
|
const promptContent = fs.readFileSync(promptPath, "utf-8");
|
||||||
|
expect(promptContent).toContain("SYSTEM:");
|
||||||
|
expect(promptContent).toContain("Test Agent Xyz");
|
||||||
|
|
||||||
|
// Check workflow file
|
||||||
|
const workflowPath = path.join(ROOT_DIR, ".github", "workflows", `${TEST_AGENT_NAME}.workflow.yml`);
|
||||||
|
expect(fs.existsSync(workflowPath)).toBe(true);
|
||||||
|
const workflowContent = fs.readFileSync(workflowPath, "utf-8");
|
||||||
|
expect(workflowContent).toContain("name: Test Agent Xyz Workflow");
|
||||||
|
expect(workflowContent).toContain("workflow_dispatch");
|
||||||
|
|
||||||
|
// Check docs file
|
||||||
|
const docPath = path.join(ROOT_DIR, "docs", "agents", `${TEST_AGENT_NAME}.mdx`);
|
||||||
|
expect(fs.existsSync(docPath)).toBe(true);
|
||||||
|
const docContent = fs.readFileSync(docPath, "utf-8");
|
||||||
|
expect(docContent).toContain("# Test Agent Xyz Agent");
|
||||||
|
expect(docContent).toContain("Auto-generated");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should convert spaces in agent name to hyphens for agent id", () => {
|
||||||
|
const agentNameWithSpaces = "my cool agent";
|
||||||
|
const expectedId = "my-cool-agent";
|
||||||
|
|
||||||
|
try {
|
||||||
|
const output = execSync(`node scripts/spawn-agent.js "${agentNameWithSpaces}"`, {
|
||||||
|
cwd: ROOT_DIR,
|
||||||
|
encoding: "utf-8",
|
||||||
|
});
|
||||||
|
expect(output).toContain(`Created agent: ${expectedId}`);
|
||||||
|
|
||||||
|
const jsonPath = path.join(ROOT_DIR, "agents", `${expectedId}.agent.json`);
|
||||||
|
expect(fs.existsSync(jsonPath)).toBe(true);
|
||||||
|
} finally {
|
||||||
|
// Cleanup
|
||||||
|
const paths = [
|
||||||
|
path.join(ROOT_DIR, "agents", `${expectedId}.agent.json`),
|
||||||
|
path.join(ROOT_DIR, "agents", `${expectedId}.prompt.txt`),
|
||||||
|
path.join(ROOT_DIR, ".github", "workflows", `${expectedId}.workflow.yml`),
|
||||||
|
path.join(ROOT_DIR, "docs", "agents", `${expectedId}.mdx`),
|
||||||
|
];
|
||||||
|
for (const p of paths) {
|
||||||
|
if (fs.existsSync(p)) {
|
||||||
|
fs.unlinkSync(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user