@tacuchi/agent-factory 0.2.0 → 0.4.0
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/bin/agent-factory.js
CHANGED
|
@@ -38,6 +38,8 @@ program
|
|
|
38
38
|
.option('-s, --scope <path>', 'Repository path (for stack detection)')
|
|
39
39
|
.option('-o, --output <path>', 'Output directory (default: current dir)')
|
|
40
40
|
.option('-t, --target <target>', 'Target: claude, codex, all', 'all')
|
|
41
|
+
.option('--stack <csv>', 'Override detected stack (comma-separated)')
|
|
42
|
+
.option('--dry-run', 'Preview generated agent without writing files')
|
|
41
43
|
.option('--tools <tools>', 'Comma-separated tools: Read,Write,Edit,Bash')
|
|
42
44
|
.option('--specialists <list>', 'CSV list of specialist agent names (for coordinator role)')
|
|
43
45
|
.option('--repo-count <n>', 'Number of repos in workspace (for coordinator role)', parseInt)
|
package/package.json
CHANGED
|
@@ -1,45 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@tacuchi/agent-factory",
|
|
3
|
-
"version": "0.2.0",
|
|
4
|
-
"description": "CLI to create AI agents for Claude Code, Codex, Gemini CLI and more",
|
|
5
|
-
"bin": {
|
|
6
|
-
"agent-factory": "bin/agent-factory.js"
|
|
7
|
-
},
|
|
8
|
-
"files": [
|
|
9
|
-
"bin/",
|
|
10
|
-
"src/",
|
|
11
|
-
"templates/",
|
|
12
|
-
"README.md",
|
|
13
|
-
"LICENSE"
|
|
14
|
-
],
|
|
15
|
-
"engines": {
|
|
16
|
-
"node": ">=16"
|
|
17
|
-
},
|
|
18
|
-
"scripts": {
|
|
19
|
-
"test": "node --test tests/",
|
|
20
|
-
"start": "node bin/agent-factory.js"
|
|
21
|
-
},
|
|
22
|
-
"keywords": [
|
|
23
|
-
"claude-code",
|
|
24
|
-
"agents",
|
|
25
|
-
"codex",
|
|
26
|
-
"gemini",
|
|
27
|
-
"ai",
|
|
28
|
-
"cli",
|
|
29
|
-
"agent-factory"
|
|
30
|
-
],
|
|
31
|
-
"author": "tacuchi",
|
|
32
|
-
"license": "MIT",
|
|
33
|
-
"repository": {
|
|
34
|
-
"type": "git",
|
|
35
|
-
"url": "https://github.com/tacuchi/agent-factory"
|
|
36
|
-
},
|
|
37
|
-
"dependencies": {
|
|
38
|
-
"chalk": "^4.1.2",
|
|
39
|
-
"commander": "^11.1.0",
|
|
40
|
-
"fs-extra": "^11.2.0",
|
|
41
|
-
"inquirer": "^8.2.6",
|
|
42
|
-
"js-yaml": "^4.1.0",
|
|
43
|
-
"ora": "^5.4.1"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
1
|
+
{"name":"@tacuchi/agent-factory","version":"0.4.0","description":"CLI to create AI agents for Claude Code, Codex, Gemini CLI and more","bin":{"agent-factory":"bin/agent-factory.js"},"files":["bin/","src/","templates/","README.md","LICENSE"],"engines":{"node":">=16"},"scripts":{"test":"node --test tests/*.test.js","start":"node bin/agent-factory.js"},"keywords":["claude-code","agents","codex","gemini","ai","cli","agent-factory"],"author":"tacuchi","license":"MIT","repository":{"type":"git","url":"https://github.com/tacuchi/agent-factory"},"dependencies":{"chalk":"^4.1.2","commander":"^11.1.0","fs-extra":"^11.2.0","inquirer":"^8.2.6","js-yaml":"^4.1.0","ora":"^5.4.1"}}
|
package/src/commands/create.js
CHANGED
|
@@ -10,7 +10,7 @@ async function runCreate(options = {}) {
|
|
|
10
10
|
const isInteractive = !options.name;
|
|
11
11
|
const config = isInteractive ? await askCreateOptions() : normalizeFlags(options);
|
|
12
12
|
|
|
13
|
-
const { name, role, model, scope, output, target, tools, specialists, repoCount, description, instructions } = config;
|
|
13
|
+
const { name, role, model, scope, output, target, tools, specialists, repoCount, description, instructions, stack, dryRun } = config;
|
|
14
14
|
|
|
15
15
|
const spin = spinner('Generating agent...').start();
|
|
16
16
|
|
|
@@ -21,13 +21,27 @@ async function runCreate(options = {}) {
|
|
|
21
21
|
spin.succeed('Custom agent generated');
|
|
22
22
|
} else {
|
|
23
23
|
let stackResult = { primaryTech: 'Generic', framework: '', verifyCommands: '', stackParts: [], stackCsv: 'Generic' };
|
|
24
|
-
if (
|
|
24
|
+
if (stack) {
|
|
25
|
+
const parts = stack.split(',').map(s => s.trim()).filter(Boolean);
|
|
26
|
+
stackResult = {
|
|
27
|
+
primaryTech: parts[0] || 'Generic',
|
|
28
|
+
framework: parts[1] || '',
|
|
29
|
+
verifyCommands: '',
|
|
30
|
+
stackParts: parts,
|
|
31
|
+
stackCsv: parts.join(', '),
|
|
32
|
+
};
|
|
33
|
+
} else if (scope) {
|
|
25
34
|
stackResult = await detect(scope);
|
|
26
35
|
}
|
|
27
36
|
|
|
37
|
+
const techLabel = stackResult.framework
|
|
38
|
+
? `${stackResult.framework} (${stackResult.primaryTech})`
|
|
39
|
+
: stackResult.primaryTech;
|
|
40
|
+
|
|
28
41
|
const templateData = {
|
|
29
42
|
name,
|
|
30
43
|
primary_tech: stackResult.primaryTech,
|
|
44
|
+
tech_label: techLabel,
|
|
31
45
|
framework: stackResult.framework,
|
|
32
46
|
scope: scope || '.',
|
|
33
47
|
stack_list: stackResult.stackParts.length > 0
|
|
@@ -38,8 +52,6 @@ async function runCreate(options = {}) {
|
|
|
38
52
|
specialist_list: formatSpecialistList(specialists),
|
|
39
53
|
N: repoCount ? String(repoCount) : '',
|
|
40
54
|
repos_word: repoCount === 1 ? 'repositorio' : 'repositorios',
|
|
41
|
-
skills_section: '',
|
|
42
|
-
mcp_section: '',
|
|
43
55
|
};
|
|
44
56
|
|
|
45
57
|
const templateFile = `${role}.md.tmpl`;
|
|
@@ -58,6 +70,13 @@ async function runCreate(options = {}) {
|
|
|
58
70
|
if (target === 'claude' || target === 'all') targetDirs.push('.claude/agents/');
|
|
59
71
|
if (target === 'codex' || target === 'all') targetDirs.push('.agents/');
|
|
60
72
|
|
|
73
|
+
if (dryRun) {
|
|
74
|
+
log.info('--- DRY RUN: Agent preview ---');
|
|
75
|
+
console.log(body);
|
|
76
|
+
log.info('--- End preview ---');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
61
80
|
if (!options.yes && isInteractive) {
|
|
62
81
|
const confirmed = await confirmGeneration(name, targetDirs);
|
|
63
82
|
if (!confirmed) {
|
|
@@ -113,6 +132,8 @@ function normalizeFlags(options) {
|
|
|
113
132
|
repoCount: options.repoCount || 0,
|
|
114
133
|
description: options.description || '',
|
|
115
134
|
instructions: options.instructions || '',
|
|
135
|
+
stack: options.stack || '',
|
|
136
|
+
dryRun: options.dryRun || false,
|
|
116
137
|
};
|
|
117
138
|
}
|
|
118
139
|
|
|
@@ -138,4 +159,4 @@ async function resolveCustomBody(instructions, name, description) {
|
|
|
138
159
|
return `# ${name}\n\n${instructions}\n`;
|
|
139
160
|
}
|
|
140
161
|
|
|
141
|
-
module.exports = { runCreate };
|
|
162
|
+
module.exports = { runCreate, normalizeFlags, formatSpecialistList };
|
package/src/core/agent-writer.js
CHANGED
|
@@ -37,7 +37,12 @@ function buildSkillsFormat(name, description, body) {
|
|
|
37
37
|
return `---\nname: ${name}\ndescription: "${description}"\n---\n\n${body}\n`;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
function ensureAgentSuffix(name) {
|
|
41
|
+
return name.endsWith('-agent') ? name : `${name}-agent`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function writeAgent({ name: rawName, role, model, tools, body, outputDir, target, description: customDesc }) {
|
|
45
|
+
const name = ensureAgentSuffix(rawName);
|
|
41
46
|
const results = { claude: null, codex: null, skills: null };
|
|
42
47
|
const description = customDesc || body.split('\n').find((l) => l.trim() && !l.startsWith('#'))?.trim() || name;
|
|
43
48
|
|
|
@@ -73,4 +78,4 @@ async function writeAgent({ name, role, model, tools, body, outputDir, target, d
|
|
|
73
78
|
return results;
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
module.exports = { writeAgent, buildClaudeFormat, buildCodexFormat, buildSkillsFormat, buildDescription, TOOLS_BY_ROLE };
|
|
81
|
+
module.exports = { writeAgent, buildClaudeFormat, buildCodexFormat, buildSkillsFormat, buildDescription, ensureAgentSuffix, TOOLS_BY_ROLE };
|
|
@@ -112,6 +112,20 @@ async function detect(repoPath) {
|
|
|
112
112
|
verifyCommands = 'npm run build, npm test';
|
|
113
113
|
stackParts.push('Node.js');
|
|
114
114
|
}
|
|
115
|
+
|
|
116
|
+
// Fallback: Node.js CLI (has bin field) or plain JS
|
|
117
|
+
if (!primaryTech && pkg) {
|
|
118
|
+
if (pkg.bin) {
|
|
119
|
+
primaryTech = 'Node.js';
|
|
120
|
+
framework = 'CLI';
|
|
121
|
+
verifyCommands = 'npm test';
|
|
122
|
+
stackParts.push('Node.js', 'CLI');
|
|
123
|
+
} else {
|
|
124
|
+
primaryTech = 'JavaScript';
|
|
125
|
+
verifyCommands = 'npm test';
|
|
126
|
+
stackParts.push('JavaScript');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
131
|
|
|
@@ -267,6 +281,26 @@ async function detect(repoPath) {
|
|
|
267
281
|
}
|
|
268
282
|
}
|
|
269
283
|
|
|
284
|
+
// --- Shell / Bash ---
|
|
285
|
+
if (!primaryTech) {
|
|
286
|
+
const shFiles = await findFiles(abs, ['.sh'], 1);
|
|
287
|
+
if (shFiles.length > 0) {
|
|
288
|
+
primaryTech = 'Bash';
|
|
289
|
+
framework = 'Shell';
|
|
290
|
+
verifyCommands = 'bash -n *.sh, shellcheck *.sh';
|
|
291
|
+
stackParts.push('Bash', 'Shell');
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// --- Makefile (standalone) ---
|
|
296
|
+
if (!primaryTech) {
|
|
297
|
+
if (await fs.pathExists(path.join(abs, 'Makefile'))) {
|
|
298
|
+
primaryTech = 'Make';
|
|
299
|
+
verifyCommands = 'make';
|
|
300
|
+
stackParts.push('Make');
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
|
|
270
304
|
// --- Supplementary ---
|
|
271
305
|
if (await fs.pathExists(path.join(abs, 'tsconfig.json'))) {
|
|
272
306
|
if (!stackParts.includes('TypeScript') && primaryTech !== 'TypeScript') {
|
|
@@ -32,5 +32,3 @@ Cada especialista opera exclusivamente dentro de su repo asignado. Para ejecutar
|
|
|
32
32
|
## Agentes globales (gestionados por el usuario)
|
|
33
33
|
|
|
34
34
|
Si el usuario ha creado agentes globales/personales en el workspace (por ejemplo, agentes transversales de arquitectura, estilo o revision de codigo), puedes invocarlos para obtener analisis cross-repo. Estos agentes son gestionados directamente por el usuario y pueden no estar presentes en todos los workspaces.
|
|
35
|
-
{{skills_section}}
|
|
36
|
-
{{mcp_section}}
|