agents.dev 1.0.1 ā 1.0.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/dist/generators/agents.js +102 -50
- package/dist/index.js +11 -2
- package/dist/parsers/markdown.js +86 -0
- package/package.json +1 -1
|
@@ -13,65 +13,66 @@ const gemini_1 = require("../transformers/gemini");
|
|
|
13
13
|
const roo_1 = require("../transformers/roo");
|
|
14
14
|
const kilo_1 = require("../transformers/kilo");
|
|
15
15
|
const opencode_1 = require("../transformers/opencode");
|
|
16
|
+
const markdown_1 = require("../parsers/markdown");
|
|
16
17
|
async function generateAgents(definitionsDir, outDir, selectedTargets) {
|
|
17
18
|
console.log(chalk_1.default.blue(`\nš¦ Building agents from ${definitionsDir}...`));
|
|
18
19
|
try {
|
|
19
20
|
if (outDir !== process.cwd()) {
|
|
20
21
|
await fs_extra_1.default.ensureDir(outDir);
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
+
// Check if input exists
|
|
24
|
+
if (!await fs_extra_1.default.pathExists(definitionsDir)) {
|
|
25
|
+
console.error(chalk_1.default.red(`Input not found: ${definitionsDir}`));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
let files = [];
|
|
29
|
+
let baseDir = definitionsDir;
|
|
30
|
+
const stats = await fs_extra_1.default.stat(definitionsDir);
|
|
31
|
+
if (stats.isFile()) {
|
|
32
|
+
baseDir = path_1.default.dirname(definitionsDir);
|
|
33
|
+
files = [path_1.default.basename(definitionsDir)];
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
files = await fs_extra_1.default.readdir(definitionsDir);
|
|
37
|
+
}
|
|
23
38
|
for (const file of files) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
39
|
+
const filePath = path_1.default.join(baseDir, file);
|
|
40
|
+
// 1. Handle YAML
|
|
41
|
+
if (file.endsWith('.yaml') || file.endsWith('.yml')) {
|
|
42
|
+
const content = await fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
43
|
+
try {
|
|
44
|
+
const rawAgent = yaml_1.default.parse(content);
|
|
45
|
+
const parseResult = types_1.AgentSchema.safeParse(rawAgent);
|
|
46
|
+
if (!parseResult.success) {
|
|
47
|
+
logValidationErrors(file, parseResult.error);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
// Use filename as slug for YAML (backward compatibility)
|
|
51
|
+
const slug = file.replace(/\.(yaml|yml)$/, '');
|
|
52
|
+
await buildAgentArtifacts(parseResult.data, slug, outDir, selectedTargets);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
console.error(chalk_1.default.red(`Error parsing YAML ${file}: ${e.message}`));
|
|
56
|
+
}
|
|
35
57
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
id: 'kilo',
|
|
56
|
-
subDir: '.kilocode/workflows',
|
|
57
|
-
ext: 'md',
|
|
58
|
-
content: (0, kilo_1.toKiloConfig)(agent),
|
|
59
|
-
name: `${slug}.md`
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
id: 'opencode',
|
|
63
|
-
subDir: '.opencode/command',
|
|
64
|
-
ext: 'md',
|
|
65
|
-
content: (0, opencode_1.toOpenCodeCommand)(agent),
|
|
66
|
-
name: `${slug}.md`
|
|
58
|
+
// 2. Handle Markdown
|
|
59
|
+
else if (file.endsWith('.md')) {
|
|
60
|
+
const content = await fs_extra_1.default.readFile(filePath, 'utf-8');
|
|
61
|
+
const agents = (0, markdown_1.parseMarkdownAgents)(content);
|
|
62
|
+
if (agents.length === 0) {
|
|
63
|
+
console.warn(chalk_1.default.yellow(`ā ļø No agents found in ${file}`));
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (const agent of agents) {
|
|
67
|
+
const parseResult = types_1.AgentSchema.safeParse(agent);
|
|
68
|
+
if (!parseResult.success) {
|
|
69
|
+
logValidationErrors(`${file} -> ${agent.name}`, parseResult.error);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Use agent name as slug for Markdown
|
|
73
|
+
const slug = toSlug(agent.name);
|
|
74
|
+
await buildAgentArtifacts(agent, slug, outDir, selectedTargets);
|
|
67
75
|
}
|
|
68
|
-
];
|
|
69
|
-
const targetsToBuild = allTargets.filter(t => selectedTargets.includes(t.id));
|
|
70
|
-
for (const target of targetsToBuild) {
|
|
71
|
-
const targetDir = path_1.default.join(outDir, target.subDir);
|
|
72
|
-
await fs_extra_1.default.ensureDir(targetDir);
|
|
73
|
-
await fs_extra_1.default.writeFile(path_1.default.join(targetDir, target.name), target.content);
|
|
74
|
-
console.log(chalk_1.default.gray(` -> ${target.subDir}/${target.name}`));
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
console.log(chalk_1.default.bold.green('\nš Build complete! Agents are ready to use.'));
|
|
@@ -81,3 +82,54 @@ async function generateAgents(definitionsDir, outDir, selectedTargets) {
|
|
|
81
82
|
process.exit(1);
|
|
82
83
|
}
|
|
83
84
|
}
|
|
85
|
+
async function buildAgentArtifacts(agent, slug, outDir, selectedTargets) {
|
|
86
|
+
const allTargets = [
|
|
87
|
+
{
|
|
88
|
+
id: 'gemini',
|
|
89
|
+
subDir: '.gemini/commands',
|
|
90
|
+
ext: 'toml',
|
|
91
|
+
content: (0, gemini_1.toGeminiSystemPrompt)(agent),
|
|
92
|
+
name: `${slug}.toml`
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'roo',
|
|
96
|
+
subDir: '.roo/commands',
|
|
97
|
+
ext: 'md',
|
|
98
|
+
content: (0, roo_1.toRooRules)(agent),
|
|
99
|
+
name: `${slug}.md`
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'kilo',
|
|
103
|
+
subDir: '.kilocode/workflows',
|
|
104
|
+
ext: 'md',
|
|
105
|
+
content: (0, kilo_1.toKiloConfig)(agent),
|
|
106
|
+
name: `${slug}.md`
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: 'opencode',
|
|
110
|
+
subDir: '.opencode/command',
|
|
111
|
+
ext: 'md',
|
|
112
|
+
content: (0, opencode_1.toOpenCodeCommand)(agent),
|
|
113
|
+
name: `${slug}.md`
|
|
114
|
+
}
|
|
115
|
+
];
|
|
116
|
+
const targetsToBuild = allTargets.filter(t => selectedTargets.includes(t.id));
|
|
117
|
+
for (const target of targetsToBuild) {
|
|
118
|
+
const targetDir = path_1.default.join(outDir, target.subDir);
|
|
119
|
+
await fs_extra_1.default.ensureDir(targetDir);
|
|
120
|
+
await fs_extra_1.default.writeFile(path_1.default.join(targetDir, target.name), target.content);
|
|
121
|
+
console.log(chalk_1.default.gray(` -> ${target.subDir}/${target.name}`));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function logValidationErrors(source, error) {
|
|
125
|
+
console.error(chalk_1.default.red(`ā Validation failed for ${source}:`));
|
|
126
|
+
error.issues.forEach((err) => {
|
|
127
|
+
console.error(chalk_1.default.red(` - ${err.path.join('.')}: ${err.message}`));
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
function toSlug(name) {
|
|
131
|
+
return name.toLowerCase()
|
|
132
|
+
.replace(/[^\w\s-]/g, '') // remove non-word chars
|
|
133
|
+
.replace(/[\s_-]+/g, '-') // collapse whitespace/underscores to hyphens
|
|
134
|
+
.replace(/^-+|-+$/g, ''); // trim hyphens
|
|
135
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -17,6 +17,7 @@ program
|
|
|
17
17
|
.description('Agent Installer CLI')
|
|
18
18
|
.version('1.0.0')
|
|
19
19
|
.option('-o, --out <dir>', 'Output directory', '.')
|
|
20
|
+
.option('-i, --input <path>', 'Input file or directory (default: definitions/ or agents.md)')
|
|
20
21
|
.option('-t, --target <targets>', 'Comma-separated target formats (gemini, roo, kilo, opencode)')
|
|
21
22
|
.action(async (options) => {
|
|
22
23
|
console.log(chalk_1.default.bold.blue('\nš Agents.dev Installer Wizard\n'));
|
|
@@ -42,7 +43,15 @@ program
|
|
|
42
43
|
console.log(chalk_1.default.gray('ā
"docs/" directory already exists.\n'));
|
|
43
44
|
}
|
|
44
45
|
// --- STEP 2: BUILD AGENTS ---
|
|
45
|
-
|
|
46
|
+
let inputPath = options.input ? path_1.default.resolve(options.input) : path_1.default.join(process.cwd(), 'definitions');
|
|
47
|
+
// If default definitions dir doesn't exist and no input specified, try agents.md
|
|
48
|
+
if (!options.input && !await fs_extra_1.default.pathExists(inputPath)) {
|
|
49
|
+
const localAgentsMd = path_1.default.join(process.cwd(), 'agents.md');
|
|
50
|
+
if (await fs_extra_1.default.pathExists(localAgentsMd)) {
|
|
51
|
+
inputPath = localAgentsMd;
|
|
52
|
+
console.log(chalk_1.default.gray(`ā¹ļø Using 'agents.md' found in root.`));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
46
55
|
const outDir = path_1.default.resolve(options.out);
|
|
47
56
|
// Determine targets
|
|
48
57
|
let selectedTargets = [];
|
|
@@ -75,6 +84,6 @@ program
|
|
|
75
84
|
console.log(chalk_1.default.yellow('No targets selected. Exiting.'));
|
|
76
85
|
return;
|
|
77
86
|
}
|
|
78
|
-
await (0, agents_1.generateAgents)(
|
|
87
|
+
await (0, agents_1.generateAgents)(inputPath, outDir, selectedTargets);
|
|
79
88
|
});
|
|
80
89
|
program.parse(process.argv);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseMarkdownAgents = parseMarkdownAgents;
|
|
4
|
+
function parseMarkdownAgents(content) {
|
|
5
|
+
const agents = [];
|
|
6
|
+
// Normalize line endings
|
|
7
|
+
const normalized = content.replace(/\r\n/g, '\n');
|
|
8
|
+
// Split by H1 headers (# Name)
|
|
9
|
+
// We use a lookahead to keep the delimiter or just split and ignore the first empty part if it starts with #
|
|
10
|
+
const parts = normalized.split(/^# /gm);
|
|
11
|
+
for (const part of parts) {
|
|
12
|
+
if (!part.trim())
|
|
13
|
+
continue;
|
|
14
|
+
const lines = part.split('\n');
|
|
15
|
+
const headerLine = lines[0].trim();
|
|
16
|
+
// Extract emoji if present at the end
|
|
17
|
+
// E.g. "Project Manager š©āš¼" -> name: "Project Manager", emoji: "š©āš¼"
|
|
18
|
+
// Simple emoji regex or just take the last char if it looks like an emoji?
|
|
19
|
+
// Let's generic split by space and check if last part is emoji-like or just treat whole as name
|
|
20
|
+
// A simplified approach: regex for emoji is complex, let's just grab the whole string as name for now,
|
|
21
|
+
// or try to extract the last non-word character if it looks like a symbol.
|
|
22
|
+
// Spec said: "# Agent Name [Emoji]"
|
|
23
|
+
const emojiMatch = headerLine.match(/^(.*?)\s+([^\w\s\d]+)$/);
|
|
24
|
+
let name = headerLine;
|
|
25
|
+
let emoji = '';
|
|
26
|
+
if (emojiMatch) {
|
|
27
|
+
name = emojiMatch[1].trim();
|
|
28
|
+
emoji = emojiMatch[2].trim();
|
|
29
|
+
}
|
|
30
|
+
const remainingLines = lines.slice(1);
|
|
31
|
+
const sectionContent = remainingLines.join('\n');
|
|
32
|
+
// Parse sections
|
|
33
|
+
// > Role
|
|
34
|
+
// ## System Prompt
|
|
35
|
+
// ## Rules
|
|
36
|
+
// ## Tools
|
|
37
|
+
let role = '';
|
|
38
|
+
let systemPrompt = '';
|
|
39
|
+
const rules = [];
|
|
40
|
+
const tools = [];
|
|
41
|
+
// Extract Role (Blockquote)
|
|
42
|
+
const roleMatch = sectionContent.match(/^\s*>\s*(.+)$/m);
|
|
43
|
+
if (roleMatch) {
|
|
44
|
+
role = roleMatch[1].trim();
|
|
45
|
+
}
|
|
46
|
+
// specific sections
|
|
47
|
+
const sections = sectionContent.split(/^## /gm);
|
|
48
|
+
for (const section of sections) {
|
|
49
|
+
const trimmed = section.trim();
|
|
50
|
+
if (!trimmed)
|
|
51
|
+
continue;
|
|
52
|
+
const sectionLines = trimmed.split('\n');
|
|
53
|
+
const sectionTitle = sectionLines[0].trim().toLowerCase();
|
|
54
|
+
const sectionBody = sectionLines.slice(1).join('\n').trim();
|
|
55
|
+
if (sectionTitle.includes('system prompt') || sectionTitle.includes('instructions')) {
|
|
56
|
+
systemPrompt = sectionBody;
|
|
57
|
+
}
|
|
58
|
+
else if (sectionTitle.includes('rules')) {
|
|
59
|
+
// Extract bullets
|
|
60
|
+
const bullets = sectionBody.split('\n')
|
|
61
|
+
.map(l => l.trim())
|
|
62
|
+
.filter(l => l.startsWith('- ') || l.startsWith('* '))
|
|
63
|
+
.map(l => l.substring(2).trim());
|
|
64
|
+
rules.push(...bullets);
|
|
65
|
+
}
|
|
66
|
+
else if (sectionTitle.includes('tools')) {
|
|
67
|
+
const bullets = sectionBody.split('\n')
|
|
68
|
+
.map(l => l.trim())
|
|
69
|
+
.filter(l => l.startsWith('- ') || l.startsWith('* '))
|
|
70
|
+
.map(l => l.substring(2).trim());
|
|
71
|
+
tools.push(...bullets);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (name) {
|
|
75
|
+
agents.push({
|
|
76
|
+
name,
|
|
77
|
+
role,
|
|
78
|
+
emoji,
|
|
79
|
+
systemPrompt,
|
|
80
|
+
rules,
|
|
81
|
+
tools
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return agents;
|
|
86
|
+
}
|