aigent-team 0.1.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/LICENSE +21 -0
- package/README.md +253 -0
- package/dist/chunk-N3RYHWTR.js +267 -0
- package/dist/cli.js +576 -0
- package/dist/index.d.ts +234 -0
- package/dist/index.js +27 -0
- package/package.json +67 -0
- package/templates/shared/git-workflow.md +44 -0
- package/templates/shared/project-conventions.md +48 -0
- package/templates/teams/ba/agent.yaml +25 -0
- package/templates/teams/ba/references/acceptance-criteria.md +87 -0
- package/templates/teams/ba/references/api-contract-design.md +110 -0
- package/templates/teams/ba/references/requirements-analysis.md +83 -0
- package/templates/teams/ba/references/user-story-mapping.md +73 -0
- package/templates/teams/ba/skill.md +85 -0
- package/templates/teams/be/agent.yaml +34 -0
- package/templates/teams/be/conventions.md +102 -0
- package/templates/teams/be/references/api-design.md +91 -0
- package/templates/teams/be/references/async-processing.md +86 -0
- package/templates/teams/be/references/auth-security.md +58 -0
- package/templates/teams/be/references/caching.md +79 -0
- package/templates/teams/be/references/database.md +65 -0
- package/templates/teams/be/references/error-handling.md +106 -0
- package/templates/teams/be/references/observability.md +83 -0
- package/templates/teams/be/references/review-checklist.md +50 -0
- package/templates/teams/be/references/testing.md +100 -0
- package/templates/teams/be/review-checklist.md +54 -0
- package/templates/teams/be/skill.md +71 -0
- package/templates/teams/devops/agent.yaml +35 -0
- package/templates/teams/devops/conventions.md +133 -0
- package/templates/teams/devops/references/ci-cd.md +218 -0
- package/templates/teams/devops/references/cost-optimization.md +218 -0
- package/templates/teams/devops/references/disaster-recovery.md +199 -0
- package/templates/teams/devops/references/docker.md +237 -0
- package/templates/teams/devops/references/infrastructure-as-code.md +238 -0
- package/templates/teams/devops/references/kubernetes.md +397 -0
- package/templates/teams/devops/references/monitoring.md +224 -0
- package/templates/teams/devops/references/review-checklist.md +149 -0
- package/templates/teams/devops/references/security.md +225 -0
- package/templates/teams/devops/review-checklist.md +72 -0
- package/templates/teams/devops/skill.md +131 -0
- package/templates/teams/fe/agent.yaml +28 -0
- package/templates/teams/fe/conventions.md +80 -0
- package/templates/teams/fe/references/accessibility.md +92 -0
- package/templates/teams/fe/references/component-architecture.md +87 -0
- package/templates/teams/fe/references/css-styling.md +89 -0
- package/templates/teams/fe/references/forms.md +73 -0
- package/templates/teams/fe/references/performance.md +104 -0
- package/templates/teams/fe/references/review-checklist.md +51 -0
- package/templates/teams/fe/references/security.md +90 -0
- package/templates/teams/fe/references/state-management.md +117 -0
- package/templates/teams/fe/references/testing.md +112 -0
- package/templates/teams/fe/review-checklist.md +53 -0
- package/templates/teams/fe/skill.md +68 -0
- package/templates/teams/lead/agent.yaml +18 -0
- package/templates/teams/lead/references/cross-team-coordination.md +68 -0
- package/templates/teams/lead/references/quality-gates.md +64 -0
- package/templates/teams/lead/references/task-decomposition.md +69 -0
- package/templates/teams/lead/skill.md +83 -0
- package/templates/teams/qa/agent.yaml +32 -0
- package/templates/teams/qa/conventions.md +130 -0
- package/templates/teams/qa/references/ci-integration.md +337 -0
- package/templates/teams/qa/references/e2e-testing.md +292 -0
- package/templates/teams/qa/references/mocking.md +249 -0
- package/templates/teams/qa/references/performance-testing.md +288 -0
- package/templates/teams/qa/references/review-checklist.md +143 -0
- package/templates/teams/qa/references/security-testing.md +271 -0
- package/templates/teams/qa/references/test-data.md +275 -0
- package/templates/teams/qa/references/test-strategy.md +192 -0
- package/templates/teams/qa/review-checklist.md +53 -0
- package/templates/teams/qa/skill.md +131 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
3
|
+
import {
|
|
4
|
+
PLATFORMS,
|
|
5
|
+
assembleReference,
|
|
6
|
+
assembleSkillIndex,
|
|
7
|
+
configExists,
|
|
8
|
+
loadAgents,
|
|
9
|
+
loadConfig
|
|
10
|
+
} from "./chunk-N3RYHWTR.js";
|
|
11
|
+
|
|
12
|
+
// bin/cli.ts
|
|
13
|
+
import { Command } from "commander";
|
|
14
|
+
|
|
15
|
+
// src/cli/init.ts
|
|
16
|
+
import { writeFileSync as writeFileSync2 } from "fs";
|
|
17
|
+
import { resolve as resolve3 } from "path";
|
|
18
|
+
import inquirer from "inquirer";
|
|
19
|
+
import chalk2 from "chalk";
|
|
20
|
+
|
|
21
|
+
// src/detectors/platform-detector.ts
|
|
22
|
+
import { execSync } from "child_process";
|
|
23
|
+
import { existsSync } from "fs";
|
|
24
|
+
import { resolve } from "path";
|
|
25
|
+
function commandExists(cmd) {
|
|
26
|
+
try {
|
|
27
|
+
execSync(`which ${cmd}`, { stdio: "ignore" });
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function detectPlatforms(cwd = process.cwd()) {
|
|
34
|
+
const results = [];
|
|
35
|
+
const claudeDir = existsSync(resolve(cwd, ".claude"));
|
|
36
|
+
const claudeCli = commandExists("claude");
|
|
37
|
+
results.push({
|
|
38
|
+
platform: "claude-code",
|
|
39
|
+
detected: claudeDir || claudeCli,
|
|
40
|
+
reason: claudeDir ? ".claude/ directory found" : claudeCli ? "claude CLI found" : "not detected"
|
|
41
|
+
});
|
|
42
|
+
const cursorDir = existsSync(resolve(cwd, ".cursor"));
|
|
43
|
+
const cursorCli = commandExists("cursor");
|
|
44
|
+
results.push({
|
|
45
|
+
platform: "cursor",
|
|
46
|
+
detected: cursorDir || cursorCli,
|
|
47
|
+
reason: cursorDir ? ".cursor/ directory found" : cursorCli ? "cursor CLI found" : "not detected"
|
|
48
|
+
});
|
|
49
|
+
const codexDir = existsSync(resolve(cwd, ".codex"));
|
|
50
|
+
const codexCli = commandExists("codex");
|
|
51
|
+
results.push({
|
|
52
|
+
platform: "codex",
|
|
53
|
+
detected: codexDir || codexCli,
|
|
54
|
+
reason: codexDir ? ".codex/ directory found" : codexCli ? "codex CLI found" : "not detected"
|
|
55
|
+
});
|
|
56
|
+
const antigravityDir = existsSync(resolve(cwd, ".agents"));
|
|
57
|
+
const geminiMd = existsSync(resolve(cwd, "GEMINI.md"));
|
|
58
|
+
const antigravityCli = commandExists("antigravity");
|
|
59
|
+
results.push({
|
|
60
|
+
platform: "antigravity",
|
|
61
|
+
detected: antigravityDir || geminiMd || antigravityCli,
|
|
62
|
+
reason: antigravityDir ? ".agents/ directory found" : geminiMd ? "GEMINI.md found" : antigravityCli ? "antigravity CLI found" : "not detected"
|
|
63
|
+
});
|
|
64
|
+
return results;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// src/cli/generate.ts
|
|
68
|
+
import { writeFileSync, mkdirSync, existsSync as existsSync2, readFileSync } from "fs";
|
|
69
|
+
import { resolve as resolve2, dirname } from "path";
|
|
70
|
+
import chalk from "chalk";
|
|
71
|
+
|
|
72
|
+
// src/compilers/base.compiler.ts
|
|
73
|
+
var BaseCompiler = class {
|
|
74
|
+
/**
|
|
75
|
+
* Compile reference files for an agent into a given directory.
|
|
76
|
+
* Returns CompiledOutput[] for each reference file.
|
|
77
|
+
*/
|
|
78
|
+
compileReferences(agent, baseDir, extension = ".md") {
|
|
79
|
+
if (!agent.references?.length) return [];
|
|
80
|
+
return agent.references.map((ref) => ({
|
|
81
|
+
filePath: `${baseDir}/${ref.id}${extension}`,
|
|
82
|
+
content: assembleReference(ref) + "\n",
|
|
83
|
+
overwriteStrategy: "replace"
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
formatFrontmatter(data) {
|
|
87
|
+
const lines = ["---"];
|
|
88
|
+
for (const [key, value] of Object.entries(data)) {
|
|
89
|
+
if (value === void 0 || value === null) continue;
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
lines.push(`${key}:`);
|
|
92
|
+
for (const item of value) {
|
|
93
|
+
lines.push(` - ${item}`);
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
lines.push(`${key}: ${JSON.stringify(value)}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
lines.push("---");
|
|
100
|
+
return lines.join("\n");
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/compilers/claude-code.compiler.ts
|
|
105
|
+
var ClaudeCodeCompiler = class extends BaseCompiler {
|
|
106
|
+
platform = "claude-code";
|
|
107
|
+
compile(agents, config) {
|
|
108
|
+
const outputs = [];
|
|
109
|
+
for (const agent of agents) {
|
|
110
|
+
const frontmatter = this.formatFrontmatter({
|
|
111
|
+
name: agent.name,
|
|
112
|
+
description: agent.description,
|
|
113
|
+
tools: agent.tools.allowed
|
|
114
|
+
});
|
|
115
|
+
const body = assembleSkillIndex(agent);
|
|
116
|
+
const content = `${frontmatter}
|
|
117
|
+
|
|
118
|
+
${body}
|
|
119
|
+
`;
|
|
120
|
+
outputs.push({
|
|
121
|
+
filePath: `.claude/agents/${agent.id}-agent.md`,
|
|
122
|
+
content,
|
|
123
|
+
overwriteStrategy: "replace"
|
|
124
|
+
});
|
|
125
|
+
const refs = this.compileReferences(
|
|
126
|
+
agent,
|
|
127
|
+
`.claude/agents/${agent.id}-agent/references`
|
|
128
|
+
);
|
|
129
|
+
outputs.push(...refs);
|
|
130
|
+
}
|
|
131
|
+
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
132
|
+
const claudeMd = [
|
|
133
|
+
`# CLAUDE.md`,
|
|
134
|
+
``,
|
|
135
|
+
`This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.`,
|
|
136
|
+
``,
|
|
137
|
+
`## Agent Team`,
|
|
138
|
+
``,
|
|
139
|
+
`This project uses aigent-team. The following specialized agents are available:`,
|
|
140
|
+
``,
|
|
141
|
+
agentList,
|
|
142
|
+
``,
|
|
143
|
+
`Use the appropriate agent for your task by invoking it from the .claude/agents/ directory.`,
|
|
144
|
+
``
|
|
145
|
+
].join("\n");
|
|
146
|
+
outputs.push({
|
|
147
|
+
filePath: "CLAUDE.md",
|
|
148
|
+
content: claudeMd,
|
|
149
|
+
overwriteStrategy: "skip-if-exists"
|
|
150
|
+
});
|
|
151
|
+
return outputs;
|
|
152
|
+
}
|
|
153
|
+
validate(outputs) {
|
|
154
|
+
const errors = [];
|
|
155
|
+
const warnings = [];
|
|
156
|
+
for (const output of outputs) {
|
|
157
|
+
if (output.filePath.includes("/references/")) continue;
|
|
158
|
+
const lineCount = output.content.split("\n").length;
|
|
159
|
+
if (lineCount > 300) {
|
|
160
|
+
warnings.push(
|
|
161
|
+
`${output.filePath}: ${lineCount} lines (recommended max 300 for Claude Code)`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
// src/compilers/cursor.compiler.ts
|
|
170
|
+
var CursorCompiler = class extends BaseCompiler {
|
|
171
|
+
platform = "cursor";
|
|
172
|
+
compile(agents, config) {
|
|
173
|
+
const outputs = [];
|
|
174
|
+
for (const agent of agents) {
|
|
175
|
+
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
176
|
+
const frontmatterData = {
|
|
177
|
+
description: agent.description.trim().split("\n")[0],
|
|
178
|
+
alwaysApply: !globs
|
|
179
|
+
};
|
|
180
|
+
if (globs) {
|
|
181
|
+
frontmatterData.globs = globs;
|
|
182
|
+
}
|
|
183
|
+
const frontmatter = this.formatFrontmatter(frontmatterData);
|
|
184
|
+
const body = assembleSkillIndex(agent);
|
|
185
|
+
const content = `${frontmatter}
|
|
186
|
+
|
|
187
|
+
${body}
|
|
188
|
+
`;
|
|
189
|
+
outputs.push({
|
|
190
|
+
filePath: `.cursor/rules/${agent.id}-agent.mdc`,
|
|
191
|
+
content,
|
|
192
|
+
overwriteStrategy: "replace"
|
|
193
|
+
});
|
|
194
|
+
if (agent.references?.length) {
|
|
195
|
+
for (const ref of agent.references) {
|
|
196
|
+
const refFrontmatter = this.formatFrontmatter({
|
|
197
|
+
description: `${agent.name} reference: ${ref.title}`,
|
|
198
|
+
alwaysApply: false,
|
|
199
|
+
globs: globs || void 0
|
|
200
|
+
});
|
|
201
|
+
outputs.push({
|
|
202
|
+
filePath: `.cursor/rules/${agent.id}-refs/${ref.id}.mdc`,
|
|
203
|
+
content: `${refFrontmatter}
|
|
204
|
+
|
|
205
|
+
${ref.content}
|
|
206
|
+
`,
|
|
207
|
+
overwriteStrategy: "replace"
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n---\n\n");
|
|
213
|
+
if (sharedKnowledge) {
|
|
214
|
+
const frontmatter = this.formatFrontmatter({
|
|
215
|
+
description: "Shared project conventions and knowledge for all team agents",
|
|
216
|
+
alwaysApply: true
|
|
217
|
+
});
|
|
218
|
+
outputs.push({
|
|
219
|
+
filePath: ".cursor/rules/shared-conventions.mdc",
|
|
220
|
+
content: `${frontmatter}
|
|
221
|
+
|
|
222
|
+
${sharedKnowledge}
|
|
223
|
+
`,
|
|
224
|
+
overwriteStrategy: "replace"
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return outputs;
|
|
228
|
+
}
|
|
229
|
+
validate(outputs) {
|
|
230
|
+
const errors = [];
|
|
231
|
+
const warnings = [];
|
|
232
|
+
for (const output of outputs) {
|
|
233
|
+
if (!output.filePath.endsWith(".mdc")) {
|
|
234
|
+
errors.push(`${output.filePath}: Cursor rules must have .mdc extension`);
|
|
235
|
+
}
|
|
236
|
+
if (!output.content.startsWith("---")) {
|
|
237
|
+
errors.push(`${output.filePath}: Missing YAML frontmatter`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
// src/compilers/codex.compiler.ts
|
|
245
|
+
var CodexCompiler = class extends BaseCompiler {
|
|
246
|
+
platform = "codex";
|
|
247
|
+
compile(agents, config) {
|
|
248
|
+
const outputs = [];
|
|
249
|
+
const sections = agents.map((agent) => {
|
|
250
|
+
const body = assembleSkillIndex(agent);
|
|
251
|
+
return `## ${agent.name} (${agent.id})
|
|
252
|
+
|
|
253
|
+
${body}`;
|
|
254
|
+
});
|
|
255
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n");
|
|
256
|
+
const agentsMd = [
|
|
257
|
+
`# Project Agents`,
|
|
258
|
+
``,
|
|
259
|
+
`This project uses specialized AI agents for different team roles.`,
|
|
260
|
+
``,
|
|
261
|
+
...sections,
|
|
262
|
+
``,
|
|
263
|
+
sharedKnowledge ? `## Shared Knowledge
|
|
264
|
+
|
|
265
|
+
${sharedKnowledge}` : ""
|
|
266
|
+
].filter(Boolean).join("\n\n");
|
|
267
|
+
outputs.push({
|
|
268
|
+
filePath: "AGENTS.md",
|
|
269
|
+
content: agentsMd + "\n",
|
|
270
|
+
overwriteStrategy: "replace"
|
|
271
|
+
});
|
|
272
|
+
for (const agent of agents) {
|
|
273
|
+
const frontmatter = this.formatFrontmatter({
|
|
274
|
+
nickname_candidates: [agent.id, agent.role],
|
|
275
|
+
model: "inherit"
|
|
276
|
+
});
|
|
277
|
+
const body = assembleSkillIndex(agent);
|
|
278
|
+
const content = `${frontmatter}
|
|
279
|
+
|
|
280
|
+
${body}
|
|
281
|
+
`;
|
|
282
|
+
outputs.push({
|
|
283
|
+
filePath: `.codex/agents/${agent.id}-agent.md`,
|
|
284
|
+
content,
|
|
285
|
+
overwriteStrategy: "replace"
|
|
286
|
+
});
|
|
287
|
+
const refs = this.compileReferences(
|
|
288
|
+
agent,
|
|
289
|
+
`.codex/agents/${agent.id}-agent/references`
|
|
290
|
+
);
|
|
291
|
+
outputs.push(...refs);
|
|
292
|
+
}
|
|
293
|
+
return outputs;
|
|
294
|
+
}
|
|
295
|
+
validate(outputs) {
|
|
296
|
+
const errors = [];
|
|
297
|
+
const warnings = [];
|
|
298
|
+
const agentsMd = outputs.find((o) => o.filePath === "AGENTS.md");
|
|
299
|
+
if (!agentsMd) {
|
|
300
|
+
errors.push("AGENTS.md is missing from compiled output");
|
|
301
|
+
}
|
|
302
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// src/compilers/antigravity.compiler.ts
|
|
307
|
+
var TOOL_MAP = {
|
|
308
|
+
Read: "read_file",
|
|
309
|
+
Write: "str_replace_editor",
|
|
310
|
+
Edit: "str_replace_editor",
|
|
311
|
+
Bash: "bash",
|
|
312
|
+
Grep: "search",
|
|
313
|
+
Glob: "list_dir"
|
|
314
|
+
};
|
|
315
|
+
var AntigravityCompiler = class extends BaseCompiler {
|
|
316
|
+
platform = "antigravity";
|
|
317
|
+
compile(agents, config) {
|
|
318
|
+
const outputs = [];
|
|
319
|
+
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
320
|
+
const geminiMd = [
|
|
321
|
+
`# Antigravity Configuration`,
|
|
322
|
+
``,
|
|
323
|
+
`## Available Agents`,
|
|
324
|
+
``,
|
|
325
|
+
agentList,
|
|
326
|
+
``,
|
|
327
|
+
`Agents are defined as skills in the \`.agents/skills/\` directory.`,
|
|
328
|
+
`Use the appropriate agent skill for team-specific tasks.`,
|
|
329
|
+
``
|
|
330
|
+
].join("\n");
|
|
331
|
+
outputs.push({
|
|
332
|
+
filePath: "GEMINI.md",
|
|
333
|
+
content: geminiMd,
|
|
334
|
+
overwriteStrategy: "replace"
|
|
335
|
+
});
|
|
336
|
+
for (const agent of agents) {
|
|
337
|
+
const allowedTools = agent.tools.allowed.map((t) => TOOL_MAP[t] || t.toLowerCase()).filter((v, i, arr) => arr.indexOf(v) === i);
|
|
338
|
+
const frontmatter = this.formatFrontmatter({
|
|
339
|
+
name: `${agent.id}-agent`,
|
|
340
|
+
description: agent.description.trim().split("\n")[0],
|
|
341
|
+
"allowed-tools": allowedTools
|
|
342
|
+
});
|
|
343
|
+
const body = assembleSkillIndex(agent);
|
|
344
|
+
const content = `${frontmatter}
|
|
345
|
+
|
|
346
|
+
${body}
|
|
347
|
+
`;
|
|
348
|
+
outputs.push({
|
|
349
|
+
filePath: `.agents/skills/${agent.id}-agent/SKILL.md`,
|
|
350
|
+
content,
|
|
351
|
+
overwriteStrategy: "replace"
|
|
352
|
+
});
|
|
353
|
+
const refs = this.compileReferences(
|
|
354
|
+
agent,
|
|
355
|
+
`.agents/skills/${agent.id}-agent/references`
|
|
356
|
+
);
|
|
357
|
+
outputs.push(...refs);
|
|
358
|
+
}
|
|
359
|
+
return outputs;
|
|
360
|
+
}
|
|
361
|
+
validate(outputs) {
|
|
362
|
+
const errors = [];
|
|
363
|
+
const warnings = [];
|
|
364
|
+
for (const output of outputs) {
|
|
365
|
+
if (output.filePath.includes("SKILL.md")) {
|
|
366
|
+
const dirName = output.filePath.split("/").slice(-2, -1)[0];
|
|
367
|
+
const nameMatch = output.content.match(/^name:\s*"?(.+?)"?\s*$/m);
|
|
368
|
+
if (nameMatch && nameMatch[1] !== dirName) {
|
|
369
|
+
errors.push(
|
|
370
|
+
`${output.filePath}: SKILL.md name "${nameMatch[1]}" does not match directory "${dirName}"`
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// src/compilers/index.ts
|
|
380
|
+
var compilers = {
|
|
381
|
+
"claude-code": () => new ClaudeCodeCompiler(),
|
|
382
|
+
cursor: () => new CursorCompiler(),
|
|
383
|
+
codex: () => new CodexCompiler(),
|
|
384
|
+
antigravity: () => new AntigravityCompiler()
|
|
385
|
+
};
|
|
386
|
+
function getAllCompilers(platforms) {
|
|
387
|
+
return platforms.map((p) => compilers[p]());
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// src/cli/generate.ts
|
|
391
|
+
function writeOutput(output, cwd) {
|
|
392
|
+
const fullPath = resolve2(cwd, output.filePath);
|
|
393
|
+
const dir = dirname(fullPath);
|
|
394
|
+
if (output.overwriteStrategy === "skip-if-exists" && existsSync2(fullPath)) {
|
|
395
|
+
return false;
|
|
396
|
+
}
|
|
397
|
+
if (output.overwriteStrategy === "merge" && existsSync2(fullPath)) {
|
|
398
|
+
const existing = readFileSync(fullPath, "utf-8");
|
|
399
|
+
if (!existing.includes("## Agent Team")) {
|
|
400
|
+
writeFileSync(fullPath, existing + "\n" + output.content);
|
|
401
|
+
return true;
|
|
402
|
+
}
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
mkdirSync(dir, { recursive: true });
|
|
406
|
+
writeFileSync(fullPath, output.content);
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
async function runGenerate(cwd = process.cwd(), options = {}) {
|
|
410
|
+
const config = await loadConfig(cwd);
|
|
411
|
+
const agents = loadAgents(config, cwd);
|
|
412
|
+
const platforms = options.platform ? [options.platform] : config.platforms;
|
|
413
|
+
const compilers2 = getAllCompilers(platforms);
|
|
414
|
+
let totalFiles = 0;
|
|
415
|
+
let totalWarnings = 0;
|
|
416
|
+
for (const compiler of compilers2) {
|
|
417
|
+
const outputs = compiler.compile(agents, config);
|
|
418
|
+
const validation = compiler.validate(outputs);
|
|
419
|
+
if (!validation.valid) {
|
|
420
|
+
console.log(chalk.red(`
|
|
421
|
+
\u2717 ${compiler.platform} validation errors:`));
|
|
422
|
+
for (const error of validation.errors) {
|
|
423
|
+
console.log(chalk.red(` - ${error}`));
|
|
424
|
+
}
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
for (const warning of validation.warnings) {
|
|
428
|
+
console.log(chalk.yellow(` \u26A0 ${warning}`));
|
|
429
|
+
totalWarnings++;
|
|
430
|
+
}
|
|
431
|
+
let written = 0;
|
|
432
|
+
for (const output of outputs) {
|
|
433
|
+
if (writeOutput(output, cwd)) {
|
|
434
|
+
written++;
|
|
435
|
+
console.log(chalk.dim(` ${output.filePath}`));
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
console.log(chalk.green(`\u2713 ${compiler.platform}: ${written} file(s) generated`));
|
|
439
|
+
totalFiles += written;
|
|
440
|
+
}
|
|
441
|
+
console.log(chalk.bold(`
|
|
442
|
+
Total: ${totalFiles} file(s) generated`));
|
|
443
|
+
if (totalWarnings > 0) {
|
|
444
|
+
console.log(chalk.yellow(`${totalWarnings} warning(s)`));
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// src/cli/init.ts
|
|
449
|
+
async function runInit(cwd = process.cwd()) {
|
|
450
|
+
console.log(chalk2.bold("\n\u{1F916} aigent-team init\n"));
|
|
451
|
+
if (configExists(cwd)) {
|
|
452
|
+
const { overwrite } = await inquirer.prompt([
|
|
453
|
+
{
|
|
454
|
+
type: "confirm",
|
|
455
|
+
name: "overwrite",
|
|
456
|
+
message: "aigent-team.config.json already exists. Overwrite?",
|
|
457
|
+
default: false
|
|
458
|
+
}
|
|
459
|
+
]);
|
|
460
|
+
if (!overwrite) {
|
|
461
|
+
console.log(chalk2.yellow("Aborted."));
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
console.log(chalk2.dim("Detecting installed AI tools..."));
|
|
466
|
+
const detections = detectPlatforms(cwd);
|
|
467
|
+
const detectedPlatforms = detections.filter((d) => d.detected);
|
|
468
|
+
if (detectedPlatforms.length > 0) {
|
|
469
|
+
console.log(chalk2.green(`Found: ${detectedPlatforms.map((d) => d.platform).join(", ")}`));
|
|
470
|
+
} else {
|
|
471
|
+
console.log(chalk2.dim("No AI tools detected. You can still select platforms manually."));
|
|
472
|
+
}
|
|
473
|
+
const answers = await inquirer.prompt([
|
|
474
|
+
{
|
|
475
|
+
type: "input",
|
|
476
|
+
name: "projectName",
|
|
477
|
+
message: "Project name:",
|
|
478
|
+
default: cwd.split("/").pop()
|
|
479
|
+
},
|
|
480
|
+
{
|
|
481
|
+
type: "checkbox",
|
|
482
|
+
name: "platforms",
|
|
483
|
+
message: "Target platforms:",
|
|
484
|
+
choices: PLATFORMS.map((p) => ({
|
|
485
|
+
name: p,
|
|
486
|
+
checked: detections.find((d) => d.platform === p)?.detected ?? false
|
|
487
|
+
})),
|
|
488
|
+
validate: (input) => input.length > 0 || "Select at least one platform"
|
|
489
|
+
},
|
|
490
|
+
{
|
|
491
|
+
type: "checkbox",
|
|
492
|
+
name: "teams",
|
|
493
|
+
message: "Team agents to enable:",
|
|
494
|
+
choices: [
|
|
495
|
+
{ name: "Lead (Tech Lead / Orchestrator)", value: "lead", checked: true },
|
|
496
|
+
{ name: "BA (Business Analyst)", value: "ba", checked: true },
|
|
497
|
+
{ name: "FE (Frontend)", value: "fe", checked: true },
|
|
498
|
+
{ name: "BE (Backend)", value: "be", checked: true },
|
|
499
|
+
{ name: "QA (Testing)", value: "qa", checked: true },
|
|
500
|
+
{ name: "DevOps (Infrastructure)", value: "devops", checked: true }
|
|
501
|
+
],
|
|
502
|
+
validate: (input) => input.length > 0 || "Select at least one team"
|
|
503
|
+
}
|
|
504
|
+
]);
|
|
505
|
+
const config = {
|
|
506
|
+
projectName: answers.projectName,
|
|
507
|
+
platforms: answers.platforms,
|
|
508
|
+
teams: answers.teams
|
|
509
|
+
};
|
|
510
|
+
const configPath = resolve3(cwd, "aigent-team.config.json");
|
|
511
|
+
writeFileSync2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
512
|
+
console.log(chalk2.green(`
|
|
513
|
+
\u2713 Created ${configPath}`));
|
|
514
|
+
console.log(chalk2.dim("\nGenerating platform configs..."));
|
|
515
|
+
await runGenerate(cwd);
|
|
516
|
+
console.log(chalk2.bold.green("\n\u2705 aigent-team initialized successfully!\n"));
|
|
517
|
+
console.log(chalk2.dim("Next steps:"));
|
|
518
|
+
console.log(chalk2.dim(" - Edit aigent-team.config.json to customize agents"));
|
|
519
|
+
console.log(chalk2.dim(" - Run `aigent-team generate` after making changes"));
|
|
520
|
+
console.log(chalk2.dim(" - Add .aigent-team/teams/<role>/ for local overrides\n"));
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/cli/validate.ts
|
|
524
|
+
import { existsSync as existsSync3 } from "fs";
|
|
525
|
+
import { resolve as resolve4 } from "path";
|
|
526
|
+
import chalk3 from "chalk";
|
|
527
|
+
async function runValidate(cwd = process.cwd()) {
|
|
528
|
+
console.log(chalk3.bold("\n\u{1F50D} Validating aigent-team configs...\n"));
|
|
529
|
+
const config = await loadConfig(cwd);
|
|
530
|
+
const agents = loadAgents(config, cwd);
|
|
531
|
+
const compilers2 = getAllCompilers(config.platforms);
|
|
532
|
+
let hasErrors = false;
|
|
533
|
+
for (const compiler of compilers2) {
|
|
534
|
+
const outputs = compiler.compile(agents, config);
|
|
535
|
+
const validation = compiler.validate(outputs);
|
|
536
|
+
if (validation.valid && validation.warnings.length === 0) {
|
|
537
|
+
console.log(chalk3.green(`\u2713 ${compiler.platform}: OK`));
|
|
538
|
+
} else {
|
|
539
|
+
for (const error of validation.errors) {
|
|
540
|
+
console.log(chalk3.red(`\u2717 ${compiler.platform}: ${error}`));
|
|
541
|
+
hasErrors = true;
|
|
542
|
+
}
|
|
543
|
+
for (const warning of validation.warnings) {
|
|
544
|
+
console.log(chalk3.yellow(`\u26A0 ${compiler.platform}: ${warning}`));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
for (const output of outputs) {
|
|
548
|
+
const fullPath = resolve4(cwd, output.filePath);
|
|
549
|
+
if (!existsSync3(fullPath)) {
|
|
550
|
+
console.log(chalk3.yellow(` \u26A0 ${output.filePath} not found on disk (run \`aigent-team generate\`)`));
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (hasErrors) {
|
|
555
|
+
console.log(chalk3.red("\n\u2717 Validation failed\n"));
|
|
556
|
+
process.exit(1);
|
|
557
|
+
} else {
|
|
558
|
+
console.log(chalk3.green("\n\u2705 All validations passed\n"));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// bin/cli.ts
|
|
563
|
+
var program = new Command();
|
|
564
|
+
program.name("aigent-team").description("Cross-platform AI agent team plugin for Claude Code, Cursor, Codex, and Antigravity").version("0.1.0");
|
|
565
|
+
program.command("init").description("Initialize aigent-team in your project (interactive)").action(async () => {
|
|
566
|
+
await runInit(process.cwd());
|
|
567
|
+
});
|
|
568
|
+
program.command("generate").description("Generate platform-specific config files from aigent-team config").option("-p, --platform <platform>", "Generate for a specific platform only").action(async (options) => {
|
|
569
|
+
await runGenerate(process.cwd(), {
|
|
570
|
+
platform: options.platform
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
program.command("validate").description("Validate generated config files against platform constraints").action(async () => {
|
|
574
|
+
await runValidate(process.cwd());
|
|
575
|
+
});
|
|
576
|
+
program.parse();
|