@monitoro/herd
Version:
Automate your browser, build AI web tools and MCP servers with Monitoro Herd
251 lines (222 loc) ⢠7.45 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
import * as promptly from 'promptly';
// @ts-ignore
import * as packageJson from '../../../package.json' with { type: "json" };
// @ts-ignore
const { version } = packageJson.default;
const prompt = promptly.default.prompt;
// Default template files content
const urlsTemplate = `import type { TrailUrl } from "@monitoro/herd";
export default [{
"id": "default-url",
"template": "https://example.com/{{param1}}/{{param2}}",
"description": "Default URL for the trail",
"examples": [
{
"param1": "value1",
"param2": "value2"
}
],
"params": {
"param1": {
"type": "string",
"description": "The first parameter"
},
"param2": {
"type": "string",
"description": "The second parameter"
}
}
}] as TrailUrl[];`;
const selectorsTemplate = `import type { TrailSelector } from "@monitoro/herd";
export default [{
"id": "default-selector",
"value": {
"data": {
"_$r": "body",
"title": { "_$": "title" },
"content": { "_$": "main" }
}
},
"description": "Default selector for extracting basic page data",
"examples": [
{
"urlId": "default-url",
"urlParams": {
"param1": "value1",
"param2": "value2"
}
}
]
}] as TrailSelector[];`;
const actionsTemplate = `import type { Device, TrailAction, TrailActionManifest, TrailRunResources } from "@monitoro/herd";
export class DefaultAction implements TrailAction {
manifest: TrailActionManifest = {
name: "default-action",
description: "Default action for the trail",
params: {
"param1": {
"type": "string",
"description": "The first parameter"
},
"param2": {
"type": "string",
"description": "The second parameter"
}
},
result: {
type: "object",
description: "Basic page data",
properties: {
title: { type: "string" },
content: { type: "string" }
}
},
examples: [{
"param1": "value1",
"param2": "value2"
}]
}
async test(device: Device, params: Record<string, any>, resources: TrailRunResources) {
try {
const result = await this.run(device, params, resources);
if (!result) {
return { status: "error", message: "No results found", result: null };
}
return { status: "success", result };
} catch (e) {
return { status: "error", message: \`Error: \${e}\`, result: null };
}
}
async run(device: Device, params: Record<string, any>, resources: TrailRunResources) {
const page = await device.newPage();
try {
// Navigate to the default URL
await page.goto(resources.url('default-url', { param1: params.param1, param2: params.param2 }));
// Extract data using the default selector
const extracted = await page.extract(resources.selector('default-selector'));
// Return the extracted data
return extracted?.data || {};
} finally {
await page.close();
}
}
}`;
// Function to create package.json with the given trail name
function createPackageJson(trailName) {
return `{
"name": "@your-org/${trailName}",
"description": "A herd.garden trail created with herd trail init",
"version": "1.0.0",
"type": "module",
"private": true,
"dependencies": {
"@monitoro/herd": "${version}"
}
}`;
}
// Function to create .gitignore file
function createGitignore() {
return `node_modules
.build
.env
.env.local
`;
}
// Function to create README.md file
function createReadme(trailName) {
return `
This is a herd.garden trail created with herd trail init.
Test all actions and selectors:
\`\`\`bash
herd trail test
\`\`\`
Test a specific action:
\`\`\`bash
herd trail test --action default-action
\`\`\`
Test a specific selector:
\`\`\`bash
herd trail test --selector default-selector
\`\`\`
Run the trail:
\`\`\`bash
herd trail run
\`\`\`
Run the trail silently (only output results):
\`\`\`bash
herd trail run --silent # or herd trail run -s
\`\`\`
## URLs
### default-url
This is the default URL for the trail.
#### Parameters
- \`param1\`: The first parameter
- \`param2\`: The second parameter
## Selectors
### default-selector
This is the default selector for the trail.
## Actions
### default-action
This is the default action for the trail.
#### Parameters
- \`param1\`: The first parameter
- \`param2\`: The second parameter
#### Result
- \`title\`: The title of the page
- \`content\`: The content of the page
`;
}
/**
* Execute the trail initialization
* Creates a new trail with default structure in the specified directory
*/
export async function execute() {
try {
// Ask for the trail name
const trailName = await prompt('š Enter a name for your new Herd trail: ');
if (!trailName) {
console.error('ā Oops! No trail name provided');
process.exit(1);
}
// Create the trail directory (use the provided name)
const trailDir = path.join(process.cwd(), trailName);
// Check if directory already exists
if (fs.existsSync(trailDir)) {
const response = await prompt(`š¤ Directory "${trailName}" already exists. Overwrite? (y/n): `);
if (response.toLowerCase() !== 'y') {
console.log('š Trail creation cancelled. No changes were made.');
process.exit(0);
}
}
else {
fs.mkdirSync(trailDir);
}
// Create the files
fs.writeFileSync(path.join(trailDir, 'urls.ts'), urlsTemplate);
fs.writeFileSync(path.join(trailDir, 'selectors.ts'), selectorsTemplate);
fs.writeFileSync(path.join(trailDir, 'actions.ts'), actionsTemplate);
fs.writeFileSync(path.join(trailDir, 'package.json'), createPackageJson(trailName));
fs.writeFileSync(path.join(trailDir, 'README.md'), createReadme(trailName));
fs.writeFileSync(path.join(trailDir, '.gitignore'), createGitignore());
console.log(`\nš Trail "${trailName}" created successfully! š`);
console.log(`\nš Files created:`);
console.log(` āā ${trailName}/urls.ts`);
console.log(` āā ${trailName}/selectors.ts`);
console.log(` āā ${trailName}/actions.ts`);
console.log(` āā ${trailName}/package.json`);
console.log(` āā ${trailName}/README.md`);
console.log(` āā ${trailName}/.gitignore`);
console.log(`\nš Ready to go! You can now:`);
console.log(` 1. cd ${trailName}`);
console.log(` 2. run \`npm install\` or \`yarn\` `);
console.log(` 3. Run your first test: herd trail test --action default-action`);
console.log(`\nš Happy trail blazing with Herd! š`);
}
catch (error) {
console.error('ā Error initializing trail:', error);
process.exit(1);
}
}