aigent-team 0.1.0 → 0.3.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/README.md +203 -23
- package/dist/{chunk-N3RYHWTR.js → chunk-RH4B2QFX.js} +72 -5
- package/dist/cli.js +1084 -167
- package/dist/index.d.ts +19 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/teams/ba/rules.md +26 -0
- package/templates/teams/ba/skills/requirement-validation.md +42 -0
- package/templates/teams/ba/skills/story-decomposition.md +47 -0
- package/templates/teams/be/rules.md +28 -0
- package/templates/teams/be/skills/api-load-test.md +45 -0
- package/templates/teams/be/skills/database-migration.md +50 -0
- package/templates/teams/devops/rules.md +28 -0
- package/templates/teams/devops/skills/health-check.md +61 -0
- package/templates/teams/devops/skills/rollback-procedure.md +56 -0
- package/templates/teams/fe/rules.md +28 -0
- package/templates/teams/fe/skills/analyze-bundle.md +42 -0
- package/templates/teams/fe/skills/component-audit.md +41 -0
- package/templates/teams/lead/rules.md +25 -0
- package/templates/teams/lead/skills/parallel-orchestration.md +46 -0
- package/templates/teams/lead/skills/sprint-review.md +38 -0
- package/templates/teams/qa/rules.md +27 -0
- package/templates/teams/qa/skills/flaky-test-diagnosis.md +50 -0
- package/templates/teams/qa/skills/generate-test-data.md +56 -0
package/dist/cli.js
CHANGED
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
GENERATE_SCOPES,
|
|
4
5
|
PLATFORMS,
|
|
6
|
+
PLUGIN_BUNDLE_DIRS,
|
|
7
|
+
TEAM_ROLES,
|
|
5
8
|
assembleReference,
|
|
9
|
+
assembleSkill,
|
|
6
10
|
assembleSkillIndex,
|
|
7
11
|
configExists,
|
|
8
12
|
loadAgents,
|
|
9
13
|
loadConfig
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-RH4B2QFX.js";
|
|
11
15
|
|
|
12
16
|
// bin/cli.ts
|
|
13
17
|
import { Command } from "commander";
|
|
18
|
+
import chalk6 from "chalk";
|
|
14
19
|
|
|
15
20
|
// src/cli/init.ts
|
|
16
|
-
import { writeFileSync
|
|
17
|
-
import { resolve as
|
|
21
|
+
import { writeFileSync } from "fs";
|
|
22
|
+
import { resolve as resolve2 } from "path";
|
|
18
23
|
import inquirer from "inquirer";
|
|
19
|
-
import
|
|
24
|
+
import chalk from "chalk";
|
|
20
25
|
|
|
21
26
|
// src/detectors/platform-detector.ts
|
|
22
27
|
import { execSync } from "child_process";
|
|
@@ -64,13 +69,132 @@ function detectPlatforms(cwd = process.cwd()) {
|
|
|
64
69
|
return results;
|
|
65
70
|
}
|
|
66
71
|
|
|
72
|
+
// src/cli/init.ts
|
|
73
|
+
async function runInit(cwd = process.cwd()) {
|
|
74
|
+
console.log(chalk.bold("\n\u{1F916} aigent-team init\n"));
|
|
75
|
+
if (configExists(cwd)) {
|
|
76
|
+
const { overwrite } = await inquirer.prompt([
|
|
77
|
+
{
|
|
78
|
+
type: "confirm",
|
|
79
|
+
name: "overwrite",
|
|
80
|
+
message: "aigent-team.config.json already exists. Overwrite?",
|
|
81
|
+
default: false
|
|
82
|
+
}
|
|
83
|
+
]);
|
|
84
|
+
if (!overwrite) {
|
|
85
|
+
console.log(chalk.yellow("Aborted."));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
console.log(chalk.dim("Detecting installed AI tools..."));
|
|
90
|
+
const detections = detectPlatforms(cwd);
|
|
91
|
+
const detectedPlatforms = detections.filter((d) => d.detected);
|
|
92
|
+
if (detectedPlatforms.length > 0) {
|
|
93
|
+
console.log(chalk.green(`Found: ${detectedPlatforms.map((d) => d.platform).join(", ")}`));
|
|
94
|
+
} else {
|
|
95
|
+
console.log(chalk.dim("No AI tools detected. You can still select platforms manually."));
|
|
96
|
+
}
|
|
97
|
+
const answers = await inquirer.prompt([
|
|
98
|
+
{
|
|
99
|
+
type: "input",
|
|
100
|
+
name: "projectName",
|
|
101
|
+
message: "Project name:",
|
|
102
|
+
default: cwd.split("/").pop()
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
type: "checkbox",
|
|
106
|
+
name: "platforms",
|
|
107
|
+
message: "Target platforms:",
|
|
108
|
+
choices: PLATFORMS.map((p) => ({
|
|
109
|
+
name: p,
|
|
110
|
+
checked: detections.find((d) => d.platform === p)?.detected ?? false
|
|
111
|
+
})),
|
|
112
|
+
validate: (input) => input.length > 0 || "Select at least one platform"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
type: "checkbox",
|
|
116
|
+
name: "teams",
|
|
117
|
+
message: "Team agents to enable:",
|
|
118
|
+
choices: [
|
|
119
|
+
{ name: "Lead (Tech Lead / Orchestrator)", value: "lead", checked: true },
|
|
120
|
+
{ name: "BA (Business Analyst)", value: "ba", checked: true },
|
|
121
|
+
{ name: "FE (Frontend)", value: "fe", checked: true },
|
|
122
|
+
{ name: "BE (Backend)", value: "be", checked: true },
|
|
123
|
+
{ name: "QA (Testing)", value: "qa", checked: true },
|
|
124
|
+
{ name: "DevOps (Infrastructure)", value: "devops", checked: true }
|
|
125
|
+
],
|
|
126
|
+
validate: (input) => input.length > 0 || "Select at least one team"
|
|
127
|
+
}
|
|
128
|
+
]);
|
|
129
|
+
const config = {
|
|
130
|
+
projectName: answers.projectName,
|
|
131
|
+
platforms: answers.platforms,
|
|
132
|
+
teams: answers.teams
|
|
133
|
+
};
|
|
134
|
+
const configPath = resolve2(cwd, "aigent-team.config.json");
|
|
135
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
136
|
+
console.log(chalk.green(`
|
|
137
|
+
\u2713 Created ${configPath}`));
|
|
138
|
+
console.log(chalk.bold.green("\n\u2705 aigent-team initialized successfully!\n"));
|
|
139
|
+
console.log(chalk.dim("Next steps:"));
|
|
140
|
+
console.log(chalk.dim(" - Review aigent-team.config.json and adjust if needed"));
|
|
141
|
+
console.log(chalk.dim(" - Run `aigent-team generate` to generate platform configs"));
|
|
142
|
+
console.log(chalk.dim(" - Use `aigent-team generate --scope agents,skills` to control what gets generated\n"));
|
|
143
|
+
}
|
|
144
|
+
|
|
67
145
|
// src/cli/generate.ts
|
|
68
|
-
import { writeFileSync, mkdirSync, existsSync as existsSync2, readFileSync } from "fs";
|
|
69
|
-
import { resolve as
|
|
70
|
-
import
|
|
146
|
+
import { writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2, readFileSync } from "fs";
|
|
147
|
+
import { resolve as resolve3, dirname } from "path";
|
|
148
|
+
import inquirer2 from "inquirer";
|
|
149
|
+
import chalk2 from "chalk";
|
|
71
150
|
|
|
72
151
|
// src/compilers/base.compiler.ts
|
|
73
152
|
var BaseCompiler = class {
|
|
153
|
+
/**
|
|
154
|
+
* Compile with scope filtering. Delegates to decomposed methods.
|
|
155
|
+
* 'all' = hub + agents + skills + references.
|
|
156
|
+
* 'plugin' is handled externally in generate.ts.
|
|
157
|
+
*/
|
|
158
|
+
compileWithScope(agents, config, scopes) {
|
|
159
|
+
const normalized = /* @__PURE__ */ new Set();
|
|
160
|
+
for (const s of scopes) {
|
|
161
|
+
if (s === "all") {
|
|
162
|
+
normalized.add("hub");
|
|
163
|
+
normalized.add("agents");
|
|
164
|
+
normalized.add("skills");
|
|
165
|
+
normalized.add("references");
|
|
166
|
+
} else {
|
|
167
|
+
normalized.add(s);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const outputs = [];
|
|
171
|
+
if (normalized.has("agents")) {
|
|
172
|
+
outputs.push(...this.compileHubFile(agents, config));
|
|
173
|
+
outputs.push(...this.compileAgentIndexes(agents, config));
|
|
174
|
+
}
|
|
175
|
+
if (normalized.has("skills")) {
|
|
176
|
+
outputs.push(...this.compileAllSkills(agents));
|
|
177
|
+
}
|
|
178
|
+
if (normalized.has("references")) {
|
|
179
|
+
outputs.push(...this.compileAllReferences(agents));
|
|
180
|
+
}
|
|
181
|
+
return outputs;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Count files per artifact category from compiled outputs.
|
|
185
|
+
* Subclasses can override to customize category detection.
|
|
186
|
+
*/
|
|
187
|
+
countArtifacts(outputs, rootDir) {
|
|
188
|
+
const counts = {};
|
|
189
|
+
const categories = ["rules", "skills", "agents", "kb", "ai"];
|
|
190
|
+
for (const cat of categories) {
|
|
191
|
+
const prefix = `${rootDir}/${cat}/`;
|
|
192
|
+
const count = outputs.filter((o) => o.filePath.startsWith(prefix)).length;
|
|
193
|
+
if (count > 0) counts[cat] = count;
|
|
194
|
+
}
|
|
195
|
+
return counts;
|
|
196
|
+
}
|
|
197
|
+
// ---- Shared helpers ----
|
|
74
198
|
/**
|
|
75
199
|
* Compile reference files for an agent into a given directory.
|
|
76
200
|
* Returns CompiledOutput[] for each reference file.
|
|
@@ -83,6 +207,18 @@ var BaseCompiler = class {
|
|
|
83
207
|
overwriteStrategy: "replace"
|
|
84
208
|
}));
|
|
85
209
|
}
|
|
210
|
+
/**
|
|
211
|
+
* Compile skill files for an agent into a given directory.
|
|
212
|
+
* Returns CompiledOutput[] for each skill file.
|
|
213
|
+
*/
|
|
214
|
+
compileSkills(agent, baseDir, extension = ".md") {
|
|
215
|
+
if (!agent.skills?.length) return [];
|
|
216
|
+
return agent.skills.map((skill) => ({
|
|
217
|
+
filePath: `${baseDir}/${skill.id}${extension}`,
|
|
218
|
+
content: assembleSkill(skill) + "\n",
|
|
219
|
+
overwriteStrategy: "replace"
|
|
220
|
+
}));
|
|
221
|
+
}
|
|
86
222
|
formatFrontmatter(data) {
|
|
87
223
|
const lines = ["---"];
|
|
88
224
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -105,6 +241,31 @@ var BaseCompiler = class {
|
|
|
105
241
|
var ClaudeCodeCompiler = class extends BaseCompiler {
|
|
106
242
|
platform = "claude-code";
|
|
107
243
|
compile(agents, config) {
|
|
244
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
245
|
+
}
|
|
246
|
+
compileHubFile(agents, _config) {
|
|
247
|
+
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
248
|
+
const claudeMd = [
|
|
249
|
+
`# CLAUDE.md`,
|
|
250
|
+
``,
|
|
251
|
+
`This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.`,
|
|
252
|
+
``,
|
|
253
|
+
`## Agent Team`,
|
|
254
|
+
``,
|
|
255
|
+
`This project uses aigent-team. The following specialized agents are available:`,
|
|
256
|
+
``,
|
|
257
|
+
agentList,
|
|
258
|
+
``,
|
|
259
|
+
`Use the appropriate agent for your task by invoking it from the .claude/agents/ directory.`,
|
|
260
|
+
``
|
|
261
|
+
].join("\n");
|
|
262
|
+
return [{
|
|
263
|
+
filePath: "CLAUDE.md",
|
|
264
|
+
content: claudeMd,
|
|
265
|
+
overwriteStrategy: "skip-if-exists"
|
|
266
|
+
}];
|
|
267
|
+
}
|
|
268
|
+
compileAgentIndexes(agents, _config) {
|
|
108
269
|
const outputs = [];
|
|
109
270
|
for (const agent of agents) {
|
|
110
271
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -122,39 +283,101 @@ ${body}
|
|
|
122
283
|
content,
|
|
123
284
|
overwriteStrategy: "replace"
|
|
124
285
|
});
|
|
125
|
-
|
|
286
|
+
}
|
|
287
|
+
return outputs;
|
|
288
|
+
}
|
|
289
|
+
compileAllSkills(agents) {
|
|
290
|
+
const outputs = [];
|
|
291
|
+
for (const agent of agents) {
|
|
292
|
+
outputs.push(...this.compileSkills(
|
|
293
|
+
agent,
|
|
294
|
+
`.claude/agents/${agent.id}-agent/skills`
|
|
295
|
+
));
|
|
296
|
+
}
|
|
297
|
+
return outputs;
|
|
298
|
+
}
|
|
299
|
+
compileAllReferences(agents) {
|
|
300
|
+
const outputs = [];
|
|
301
|
+
for (const agent of agents) {
|
|
302
|
+
outputs.push(...this.compileReferences(
|
|
126
303
|
agent,
|
|
127
304
|
`.claude/agents/${agent.id}-agent/references`
|
|
128
|
-
);
|
|
129
|
-
outputs.push(...refs);
|
|
305
|
+
));
|
|
130
306
|
}
|
|
307
|
+
return outputs;
|
|
308
|
+
}
|
|
309
|
+
compilePluginBundle(agents, config, rootDir) {
|
|
310
|
+
const outputs = [];
|
|
131
311
|
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
312
|
outputs.push({
|
|
147
|
-
filePath:
|
|
148
|
-
content:
|
|
149
|
-
|
|
313
|
+
filePath: `${rootDir}/rules/CLAUDE.md`,
|
|
314
|
+
content: [
|
|
315
|
+
`# CLAUDE.md`,
|
|
316
|
+
``,
|
|
317
|
+
`This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.`,
|
|
318
|
+
``,
|
|
319
|
+
`## Agent Team`,
|
|
320
|
+
``,
|
|
321
|
+
`This project uses aigent-team. The following specialized agents are available:`,
|
|
322
|
+
``,
|
|
323
|
+
agentList,
|
|
324
|
+
``,
|
|
325
|
+
`Use the appropriate agent for your task by invoking it from the agents/ directory.`,
|
|
326
|
+
``
|
|
327
|
+
].join("\n"),
|
|
328
|
+
overwriteStrategy: "replace"
|
|
150
329
|
});
|
|
330
|
+
for (const agent of agents) {
|
|
331
|
+
const frontmatter = this.formatFrontmatter({
|
|
332
|
+
name: agent.name,
|
|
333
|
+
description: agent.description,
|
|
334
|
+
tools: agent.tools.allowed
|
|
335
|
+
});
|
|
336
|
+
const body = assembleSkillIndex(agent);
|
|
337
|
+
outputs.push({
|
|
338
|
+
filePath: `${rootDir}/agents/${agent.id}-agent.md`,
|
|
339
|
+
content: `${frontmatter}
|
|
340
|
+
|
|
341
|
+
${body}
|
|
342
|
+
`,
|
|
343
|
+
overwriteStrategy: "replace"
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
for (const agent of agents) {
|
|
347
|
+
if (!agent.skills?.length) continue;
|
|
348
|
+
for (const skill of agent.skills) {
|
|
349
|
+
outputs.push({
|
|
350
|
+
filePath: `${rootDir}/skills/${agent.id}/${skill.id}.md`,
|
|
351
|
+
content: assembleSkill(skill) + "\n",
|
|
352
|
+
overwriteStrategy: "replace"
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
for (const agent of agents) {
|
|
357
|
+
if (!agent.references?.length) continue;
|
|
358
|
+
for (const ref of agent.references) {
|
|
359
|
+
outputs.push({
|
|
360
|
+
filePath: `${rootDir}/kb/${agent.id}/${ref.id}.md`,
|
|
361
|
+
content: assembleReference(ref) + "\n",
|
|
362
|
+
overwriteStrategy: "replace"
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v);
|
|
367
|
+
for (let i = 0; i < sharedKnowledge.length; i++) {
|
|
368
|
+
outputs.push({
|
|
369
|
+
filePath: `${rootDir}/kb/shared/knowledge-${i + 1}.md`,
|
|
370
|
+
content: sharedKnowledge[i] + "\n",
|
|
371
|
+
overwriteStrategy: "replace"
|
|
372
|
+
});
|
|
373
|
+
}
|
|
151
374
|
return outputs;
|
|
152
375
|
}
|
|
153
376
|
validate(outputs) {
|
|
154
377
|
const errors = [];
|
|
155
378
|
const warnings = [];
|
|
156
379
|
for (const output of outputs) {
|
|
157
|
-
if (output.filePath.includes("/references/")) continue;
|
|
380
|
+
if (output.filePath.includes("/references/") || output.filePath.includes("/skills/")) continue;
|
|
158
381
|
const lineCount = output.content.split("\n").length;
|
|
159
382
|
if (lineCount > 300) {
|
|
160
383
|
warnings.push(
|
|
@@ -166,10 +389,38 @@ ${body}
|
|
|
166
389
|
}
|
|
167
390
|
};
|
|
168
391
|
|
|
392
|
+
// src/compilers/cursor-ide-plugin.compiler.ts
|
|
393
|
+
function toKebabCursorPluginId(projectName) {
|
|
394
|
+
const s = projectName.toLowerCase().replace(/[^a-z0-9.-]+/g, "-").replace(/^-+|-+$/g, "").replace(/\.{2,}/g, ".");
|
|
395
|
+
if (!s || !/^[a-z0-9]/.test(s)) {
|
|
396
|
+
return `aigent-team-${s || "pack"}`.replace(/^-+/, "");
|
|
397
|
+
}
|
|
398
|
+
return s;
|
|
399
|
+
}
|
|
400
|
+
|
|
169
401
|
// src/compilers/cursor.compiler.ts
|
|
170
402
|
var CursorCompiler = class extends BaseCompiler {
|
|
171
403
|
platform = "cursor";
|
|
172
404
|
compile(agents, config) {
|
|
405
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
406
|
+
}
|
|
407
|
+
compileHubFile(agents, _config) {
|
|
408
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n---\n\n");
|
|
409
|
+
if (!sharedKnowledge) return [];
|
|
410
|
+
const frontmatter = this.formatFrontmatter({
|
|
411
|
+
description: "Shared project conventions and knowledge for all team agents",
|
|
412
|
+
alwaysApply: true
|
|
413
|
+
});
|
|
414
|
+
return [{
|
|
415
|
+
filePath: ".cursor/rules/shared-conventions.mdc",
|
|
416
|
+
content: `${frontmatter}
|
|
417
|
+
|
|
418
|
+
${sharedKnowledge}
|
|
419
|
+
`,
|
|
420
|
+
overwriteStrategy: "replace"
|
|
421
|
+
}];
|
|
422
|
+
}
|
|
423
|
+
compileAgentIndexes(agents, _config) {
|
|
173
424
|
const outputs = [];
|
|
174
425
|
for (const agent of agents) {
|
|
175
426
|
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
@@ -191,24 +442,74 @@ ${body}
|
|
|
191
442
|
content,
|
|
192
443
|
overwriteStrategy: "replace"
|
|
193
444
|
});
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
445
|
+
}
|
|
446
|
+
return outputs;
|
|
447
|
+
}
|
|
448
|
+
compileAllSkills(agents) {
|
|
449
|
+
const outputs = [];
|
|
450
|
+
for (const agent of agents) {
|
|
451
|
+
if (!agent.skills?.length) continue;
|
|
452
|
+
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
453
|
+
for (const skill of agent.skills) {
|
|
454
|
+
const skillFrontmatter = this.formatFrontmatter({
|
|
455
|
+
description: `${agent.name} skill: ${skill.name}`,
|
|
456
|
+
alwaysApply: false,
|
|
457
|
+
globs: globs || void 0
|
|
458
|
+
});
|
|
459
|
+
outputs.push({
|
|
460
|
+
filePath: `.cursor/rules/${agent.id}-skills/${skill.id}.mdc`,
|
|
461
|
+
content: `${skillFrontmatter}
|
|
462
|
+
|
|
463
|
+
${skill.content}
|
|
464
|
+
`,
|
|
465
|
+
overwriteStrategy: "replace"
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return outputs;
|
|
470
|
+
}
|
|
471
|
+
compileAllReferences(agents) {
|
|
472
|
+
const outputs = [];
|
|
473
|
+
for (const agent of agents) {
|
|
474
|
+
if (!agent.references?.length) continue;
|
|
475
|
+
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
476
|
+
for (const ref of agent.references) {
|
|
477
|
+
const refFrontmatter = this.formatFrontmatter({
|
|
478
|
+
description: `${agent.name} reference: ${ref.title}`,
|
|
479
|
+
alwaysApply: false,
|
|
480
|
+
globs: globs || void 0
|
|
481
|
+
});
|
|
482
|
+
outputs.push({
|
|
483
|
+
filePath: `.cursor/rules/${agent.id}-refs/${ref.id}.mdc`,
|
|
484
|
+
content: `${refFrontmatter}
|
|
204
485
|
|
|
205
486
|
${ref.content}
|
|
206
487
|
`,
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
}
|
|
488
|
+
overwriteStrategy: "replace"
|
|
489
|
+
});
|
|
210
490
|
}
|
|
211
491
|
}
|
|
492
|
+
return outputs;
|
|
493
|
+
}
|
|
494
|
+
compilePluginBundle(agents, config, rootDir) {
|
|
495
|
+
const outputs = [];
|
|
496
|
+
const pluginId = toKebabCursorPluginId(config.projectName);
|
|
497
|
+
const firstLine = (text) => text.trim().split("\n")[0] ?? "";
|
|
498
|
+
outputs.push({
|
|
499
|
+
filePath: `${rootDir}/.cursor-plugin/plugin.json`,
|
|
500
|
+
content: JSON.stringify(
|
|
501
|
+
{
|
|
502
|
+
name: pluginId,
|
|
503
|
+
version: "0.1.0",
|
|
504
|
+
description: `Agent team pack for ${config.projectName} (generated by aigent-team)`,
|
|
505
|
+
keywords: ["aigent-team", "agents"],
|
|
506
|
+
author: { name: "aigent-team" }
|
|
507
|
+
},
|
|
508
|
+
null,
|
|
509
|
+
2
|
|
510
|
+
) + "\n",
|
|
511
|
+
overwriteStrategy: "replace"
|
|
512
|
+
});
|
|
212
513
|
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n---\n\n");
|
|
213
514
|
if (sharedKnowledge) {
|
|
214
515
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -216,7 +517,7 @@ ${ref.content}
|
|
|
216
517
|
alwaysApply: true
|
|
217
518
|
});
|
|
218
519
|
outputs.push({
|
|
219
|
-
filePath:
|
|
520
|
+
filePath: `${rootDir}/rules/shared-conventions.mdc`,
|
|
220
521
|
content: `${frontmatter}
|
|
221
522
|
|
|
222
523
|
${sharedKnowledge}
|
|
@@ -224,6 +525,62 @@ ${sharedKnowledge}
|
|
|
224
525
|
overwriteStrategy: "replace"
|
|
225
526
|
});
|
|
226
527
|
}
|
|
528
|
+
for (const agent of agents) {
|
|
529
|
+
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
530
|
+
const frontmatterData = {
|
|
531
|
+
description: firstLine(agent.description),
|
|
532
|
+
alwaysApply: !globs
|
|
533
|
+
};
|
|
534
|
+
if (globs) frontmatterData.globs = globs;
|
|
535
|
+
const frontmatter = this.formatFrontmatter(frontmatterData);
|
|
536
|
+
const body = assembleSkillIndex(agent);
|
|
537
|
+
outputs.push({
|
|
538
|
+
filePath: `${rootDir}/agents/${agent.id}-agent.mdc`,
|
|
539
|
+
content: `${frontmatter}
|
|
540
|
+
|
|
541
|
+
${body}
|
|
542
|
+
`,
|
|
543
|
+
overwriteStrategy: "replace"
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
for (const agent of agents) {
|
|
547
|
+
if (!agent.skills?.length) continue;
|
|
548
|
+
for (const skill of agent.skills) {
|
|
549
|
+
const skillId = `${agent.id}-${skill.id}`;
|
|
550
|
+
const descSource = skill.description?.trim() || skill.name?.trim() || skill.trigger?.trim() || `Procedure for ${agent.name}`;
|
|
551
|
+
const skillFrontmatter = this.formatFrontmatter({
|
|
552
|
+
name: skillId,
|
|
553
|
+
description: firstLine(descSource)
|
|
554
|
+
});
|
|
555
|
+
outputs.push({
|
|
556
|
+
filePath: `${rootDir}/skills/${skillId}/SKILL.md`,
|
|
557
|
+
content: `${skillFrontmatter}
|
|
558
|
+
|
|
559
|
+
${assembleSkill(skill)}
|
|
560
|
+
`,
|
|
561
|
+
overwriteStrategy: "replace"
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
for (const agent of agents) {
|
|
566
|
+
if (!agent.references?.length) continue;
|
|
567
|
+
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
568
|
+
for (const ref of agent.references) {
|
|
569
|
+
const refFrontmatter = this.formatFrontmatter({
|
|
570
|
+
description: `${agent.name} reference: ${ref.title}`,
|
|
571
|
+
alwaysApply: false,
|
|
572
|
+
globs: globs || void 0
|
|
573
|
+
});
|
|
574
|
+
outputs.push({
|
|
575
|
+
filePath: `${rootDir}/kb/${agent.id}-refs/${ref.id}.mdc`,
|
|
576
|
+
content: `${refFrontmatter}
|
|
577
|
+
|
|
578
|
+
${assembleReference(ref)}
|
|
579
|
+
`,
|
|
580
|
+
overwriteStrategy: "replace"
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
}
|
|
227
584
|
return outputs;
|
|
228
585
|
}
|
|
229
586
|
validate(outputs) {
|
|
@@ -245,7 +602,9 @@ ${sharedKnowledge}
|
|
|
245
602
|
var CodexCompiler = class extends BaseCompiler {
|
|
246
603
|
platform = "codex";
|
|
247
604
|
compile(agents, config) {
|
|
248
|
-
|
|
605
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
606
|
+
}
|
|
607
|
+
compileHubFile(agents, _config) {
|
|
249
608
|
const sections = agents.map((agent) => {
|
|
250
609
|
const body = assembleSkillIndex(agent);
|
|
251
610
|
return `## ${agent.name} (${agent.id})
|
|
@@ -264,11 +623,14 @@ ${body}`;
|
|
|
264
623
|
|
|
265
624
|
${sharedKnowledge}` : ""
|
|
266
625
|
].filter(Boolean).join("\n\n");
|
|
267
|
-
|
|
626
|
+
return [{
|
|
268
627
|
filePath: "AGENTS.md",
|
|
269
628
|
content: agentsMd + "\n",
|
|
270
629
|
overwriteStrategy: "replace"
|
|
271
|
-
}
|
|
630
|
+
}];
|
|
631
|
+
}
|
|
632
|
+
compileAgentIndexes(agents, _config) {
|
|
633
|
+
const outputs = [];
|
|
272
634
|
for (const agent of agents) {
|
|
273
635
|
const frontmatter = this.formatFrontmatter({
|
|
274
636
|
nickname_candidates: [agent.id, agent.role],
|
|
@@ -284,30 +646,107 @@ ${body}
|
|
|
284
646
|
content,
|
|
285
647
|
overwriteStrategy: "replace"
|
|
286
648
|
});
|
|
287
|
-
|
|
649
|
+
}
|
|
650
|
+
return outputs;
|
|
651
|
+
}
|
|
652
|
+
compileAllSkills(agents) {
|
|
653
|
+
const outputs = [];
|
|
654
|
+
for (const agent of agents) {
|
|
655
|
+
outputs.push(...this.compileSkills(
|
|
288
656
|
agent,
|
|
289
|
-
`.codex/agents/${agent.id}-agent/
|
|
290
|
-
);
|
|
291
|
-
outputs.push(...refs);
|
|
657
|
+
`.codex/agents/${agent.id}-agent/skills`
|
|
658
|
+
));
|
|
292
659
|
}
|
|
293
660
|
return outputs;
|
|
294
661
|
}
|
|
295
|
-
|
|
296
|
-
const
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
662
|
+
compileAllReferences(agents) {
|
|
663
|
+
const outputs = [];
|
|
664
|
+
for (const agent of agents) {
|
|
665
|
+
outputs.push(...this.compileReferences(
|
|
666
|
+
agent,
|
|
667
|
+
`.codex/agents/${agent.id}-agent/references`
|
|
668
|
+
));
|
|
301
669
|
}
|
|
302
|
-
return
|
|
670
|
+
return outputs;
|
|
303
671
|
}
|
|
304
|
-
|
|
672
|
+
compilePluginBundle(agents, _config, rootDir) {
|
|
673
|
+
const outputs = [];
|
|
674
|
+
const sections = agents.map((agent) => {
|
|
675
|
+
const body = assembleSkillIndex(agent);
|
|
676
|
+
return `## ${agent.name} (${agent.id})
|
|
305
677
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
678
|
+
${body}`;
|
|
679
|
+
});
|
|
680
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n");
|
|
681
|
+
const agentsMd = [
|
|
682
|
+
`# Project Agents`,
|
|
683
|
+
``,
|
|
684
|
+
`This project uses specialized AI agents for different team roles.`,
|
|
685
|
+
``,
|
|
686
|
+
...sections,
|
|
687
|
+
``,
|
|
688
|
+
sharedKnowledge ? `## Shared Knowledge
|
|
689
|
+
|
|
690
|
+
${sharedKnowledge}` : ""
|
|
691
|
+
].filter(Boolean).join("\n\n");
|
|
692
|
+
outputs.push({
|
|
693
|
+
filePath: `${rootDir}/rules/AGENTS.md`,
|
|
694
|
+
content: agentsMd + "\n",
|
|
695
|
+
overwriteStrategy: "replace"
|
|
696
|
+
});
|
|
697
|
+
for (const agent of agents) {
|
|
698
|
+
const frontmatter = this.formatFrontmatter({
|
|
699
|
+
nickname_candidates: [agent.id, agent.role],
|
|
700
|
+
model: "inherit"
|
|
701
|
+
});
|
|
702
|
+
const body = assembleSkillIndex(agent);
|
|
703
|
+
outputs.push({
|
|
704
|
+
filePath: `${rootDir}/agents/${agent.id}-agent.md`,
|
|
705
|
+
content: `${frontmatter}
|
|
706
|
+
|
|
707
|
+
${body}
|
|
708
|
+
`,
|
|
709
|
+
overwriteStrategy: "replace"
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
for (const agent of agents) {
|
|
713
|
+
if (!agent.skills?.length) continue;
|
|
714
|
+
for (const skill of agent.skills) {
|
|
715
|
+
outputs.push({
|
|
716
|
+
filePath: `${rootDir}/skills/${agent.id}/${skill.id}.md`,
|
|
717
|
+
content: assembleSkill(skill) + "\n",
|
|
718
|
+
overwriteStrategy: "replace"
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
for (const agent of agents) {
|
|
723
|
+
if (!agent.references?.length) continue;
|
|
724
|
+
for (const ref of agent.references) {
|
|
725
|
+
outputs.push({
|
|
726
|
+
filePath: `${rootDir}/kb/${agent.id}/${ref.id}.md`,
|
|
727
|
+
content: assembleReference(ref) + "\n",
|
|
728
|
+
overwriteStrategy: "replace"
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
return outputs;
|
|
733
|
+
}
|
|
734
|
+
validate(outputs) {
|
|
735
|
+
const errors = [];
|
|
736
|
+
const warnings = [];
|
|
737
|
+
const agentsMd = outputs.find((o) => o.filePath === "AGENTS.md");
|
|
738
|
+
if (!agentsMd) {
|
|
739
|
+
errors.push("AGENTS.md is missing from compiled output");
|
|
740
|
+
}
|
|
741
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
// src/compilers/antigravity.compiler.ts
|
|
746
|
+
var TOOL_MAP = {
|
|
747
|
+
Read: "read_file",
|
|
748
|
+
Write: "str_replace_editor",
|
|
749
|
+
Edit: "str_replace_editor",
|
|
311
750
|
Bash: "bash",
|
|
312
751
|
Grep: "search",
|
|
313
752
|
Glob: "list_dir"
|
|
@@ -315,7 +754,9 @@ var TOOL_MAP = {
|
|
|
315
754
|
var AntigravityCompiler = class extends BaseCompiler {
|
|
316
755
|
platform = "antigravity";
|
|
317
756
|
compile(agents, config) {
|
|
318
|
-
|
|
757
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
758
|
+
}
|
|
759
|
+
compileHubFile(agents, _config) {
|
|
319
760
|
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
320
761
|
const geminiMd = [
|
|
321
762
|
`# Antigravity Configuration`,
|
|
@@ -328,11 +769,14 @@ var AntigravityCompiler = class extends BaseCompiler {
|
|
|
328
769
|
`Use the appropriate agent skill for team-specific tasks.`,
|
|
329
770
|
``
|
|
330
771
|
].join("\n");
|
|
331
|
-
|
|
772
|
+
return [{
|
|
332
773
|
filePath: "GEMINI.md",
|
|
333
774
|
content: geminiMd,
|
|
334
775
|
overwriteStrategy: "replace"
|
|
335
|
-
}
|
|
776
|
+
}];
|
|
777
|
+
}
|
|
778
|
+
compileAgentIndexes(agents, _config) {
|
|
779
|
+
const outputs = [];
|
|
336
780
|
for (const agent of agents) {
|
|
337
781
|
const allowedTools = agent.tools.allowed.map((t) => TOOL_MAP[t] || t.toLowerCase()).filter((v, i, arr) => arr.indexOf(v) === i);
|
|
338
782
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -350,11 +794,91 @@ ${body}
|
|
|
350
794
|
content,
|
|
351
795
|
overwriteStrategy: "replace"
|
|
352
796
|
});
|
|
353
|
-
|
|
797
|
+
}
|
|
798
|
+
return outputs;
|
|
799
|
+
}
|
|
800
|
+
compileAllSkills(agents) {
|
|
801
|
+
const outputs = [];
|
|
802
|
+
for (const agent of agents) {
|
|
803
|
+
outputs.push(...this.compileSkills(
|
|
804
|
+
agent,
|
|
805
|
+
`.agents/skills/${agent.id}-agent/skills`
|
|
806
|
+
));
|
|
807
|
+
}
|
|
808
|
+
return outputs;
|
|
809
|
+
}
|
|
810
|
+
compileAllReferences(agents) {
|
|
811
|
+
const outputs = [];
|
|
812
|
+
for (const agent of agents) {
|
|
813
|
+
outputs.push(...this.compileReferences(
|
|
354
814
|
agent,
|
|
355
815
|
`.agents/skills/${agent.id}-agent/references`
|
|
356
|
-
);
|
|
357
|
-
|
|
816
|
+
));
|
|
817
|
+
}
|
|
818
|
+
return outputs;
|
|
819
|
+
}
|
|
820
|
+
compilePluginBundle(agents, _config, rootDir) {
|
|
821
|
+
const outputs = [];
|
|
822
|
+
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
823
|
+
outputs.push({
|
|
824
|
+
filePath: `${rootDir}/rules/GEMINI.md`,
|
|
825
|
+
content: [
|
|
826
|
+
`# Antigravity Configuration`,
|
|
827
|
+
``,
|
|
828
|
+
`## Available Agents`,
|
|
829
|
+
``,
|
|
830
|
+
agentList,
|
|
831
|
+
``,
|
|
832
|
+
`Agents are defined in the agents/ directory.`,
|
|
833
|
+
`Use the appropriate agent for team-specific tasks.`,
|
|
834
|
+
``
|
|
835
|
+
].join("\n"),
|
|
836
|
+
overwriteStrategy: "replace"
|
|
837
|
+
});
|
|
838
|
+
for (const agent of agents) {
|
|
839
|
+
const allowedTools = agent.tools.allowed.map((t) => TOOL_MAP[t] || t.toLowerCase()).filter((v, i, arr) => arr.indexOf(v) === i);
|
|
840
|
+
const frontmatter = this.formatFrontmatter({
|
|
841
|
+
name: `${agent.id}-agent`,
|
|
842
|
+
description: agent.description.trim().split("\n")[0],
|
|
843
|
+
"allowed-tools": allowedTools
|
|
844
|
+
});
|
|
845
|
+
const body = assembleSkillIndex(agent);
|
|
846
|
+
outputs.push({
|
|
847
|
+
filePath: `${rootDir}/agents/${agent.id}-agent/SKILL.md`,
|
|
848
|
+
content: `${frontmatter}
|
|
849
|
+
|
|
850
|
+
${body}
|
|
851
|
+
`,
|
|
852
|
+
overwriteStrategy: "replace"
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
for (const agent of agents) {
|
|
856
|
+
if (!agent.skills?.length) continue;
|
|
857
|
+
for (const skill of agent.skills) {
|
|
858
|
+
outputs.push({
|
|
859
|
+
filePath: `${rootDir}/skills/${agent.id}/${skill.id}.md`,
|
|
860
|
+
content: assembleSkill(skill) + "\n",
|
|
861
|
+
overwriteStrategy: "replace"
|
|
862
|
+
});
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
for (const agent of agents) {
|
|
866
|
+
if (!agent.references?.length) continue;
|
|
867
|
+
for (const ref of agent.references) {
|
|
868
|
+
outputs.push({
|
|
869
|
+
filePath: `${rootDir}/kb/${agent.id}/${ref.id}.md`,
|
|
870
|
+
content: assembleReference(ref) + "\n",
|
|
871
|
+
overwriteStrategy: "replace"
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v);
|
|
876
|
+
for (let i = 0; i < sharedKnowledge.length; i++) {
|
|
877
|
+
outputs.push({
|
|
878
|
+
filePath: `${rootDir}/kb/shared/knowledge-${i + 1}.md`,
|
|
879
|
+
content: sharedKnowledge[i] + "\n",
|
|
880
|
+
overwriteStrategy: "replace"
|
|
881
|
+
});
|
|
358
882
|
}
|
|
359
883
|
return outputs;
|
|
360
884
|
}
|
|
@@ -383,13 +907,66 @@ var compilers = {
|
|
|
383
907
|
codex: () => new CodexCompiler(),
|
|
384
908
|
antigravity: () => new AntigravityCompiler()
|
|
385
909
|
};
|
|
910
|
+
function getCompiler(platform) {
|
|
911
|
+
return compilers[platform]();
|
|
912
|
+
}
|
|
386
913
|
function getAllCompilers(platforms) {
|
|
387
914
|
return platforms.map((p) => compilers[p]());
|
|
388
915
|
}
|
|
389
916
|
|
|
917
|
+
// src/compilers/plugin.compiler.ts
|
|
918
|
+
var PluginCompiler = class {
|
|
919
|
+
compilePlugin(agents, config, pluginDir = ".aigent-team-plugin") {
|
|
920
|
+
const outputs = [];
|
|
921
|
+
const bundles = [];
|
|
922
|
+
for (const platform of config.platforms) {
|
|
923
|
+
const bundleDir = PLUGIN_BUNDLE_DIRS[platform];
|
|
924
|
+
const rootDir = `${pluginDir}/${bundleDir}`;
|
|
925
|
+
const compiler = getCompiler(platform);
|
|
926
|
+
const bundleOutputs = compiler.compilePluginBundle(agents, config, rootDir);
|
|
927
|
+
outputs.push(...bundleOutputs);
|
|
928
|
+
bundles.push({
|
|
929
|
+
platform,
|
|
930
|
+
directory: bundleDir,
|
|
931
|
+
artifacts: compiler.countArtifacts(bundleOutputs, rootDir)
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
const agentsMeta = agents.map((a) => ({
|
|
935
|
+
id: a.id,
|
|
936
|
+
name: a.name,
|
|
937
|
+
description: a.description,
|
|
938
|
+
role: a.role,
|
|
939
|
+
tools: { allowed: [...a.tools.allowed], ...a.tools.denied ? { denied: [...a.tools.denied] } : {} },
|
|
940
|
+
...a.globs?.length ? { globs: [...a.globs] } : {}
|
|
941
|
+
}));
|
|
942
|
+
const manifest = {
|
|
943
|
+
name: config.projectName,
|
|
944
|
+
version: "0.1.0",
|
|
945
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
946
|
+
generator: "aigent-team",
|
|
947
|
+
projectName: config.projectName,
|
|
948
|
+
roles: [...config.teams],
|
|
949
|
+
platforms: [...config.platforms],
|
|
950
|
+
agents: agentsMeta,
|
|
951
|
+
files: {
|
|
952
|
+
agents: agents.length,
|
|
953
|
+
skills: agents.reduce((sum, a) => sum + a.skills.length, 0),
|
|
954
|
+
references: agents.reduce((sum, a) => sum + a.references.length, 0)
|
|
955
|
+
},
|
|
956
|
+
bundles
|
|
957
|
+
};
|
|
958
|
+
outputs.push({
|
|
959
|
+
filePath: `${pluginDir}/manifest.json`,
|
|
960
|
+
content: JSON.stringify(manifest, null, 2) + "\n",
|
|
961
|
+
overwriteStrategy: "replace"
|
|
962
|
+
});
|
|
963
|
+
return outputs;
|
|
964
|
+
}
|
|
965
|
+
};
|
|
966
|
+
|
|
390
967
|
// src/cli/generate.ts
|
|
391
968
|
function writeOutput(output, cwd) {
|
|
392
|
-
const fullPath =
|
|
969
|
+
const fullPath = resolve3(cwd, output.filePath);
|
|
393
970
|
const dir = dirname(fullPath);
|
|
394
971
|
if (output.overwriteStrategy === "skip-if-exists" && existsSync2(fullPath)) {
|
|
395
972
|
return false;
|
|
@@ -397,129 +974,129 @@ function writeOutput(output, cwd) {
|
|
|
397
974
|
if (output.overwriteStrategy === "merge" && existsSync2(fullPath)) {
|
|
398
975
|
const existing = readFileSync(fullPath, "utf-8");
|
|
399
976
|
if (!existing.includes("## Agent Team")) {
|
|
400
|
-
|
|
977
|
+
writeFileSync2(fullPath, existing + "\n" + output.content);
|
|
401
978
|
return true;
|
|
402
979
|
}
|
|
403
980
|
return false;
|
|
404
981
|
}
|
|
405
|
-
|
|
406
|
-
|
|
982
|
+
mkdirSync2(dir, { recursive: true });
|
|
983
|
+
writeFileSync2(fullPath, output.content);
|
|
407
984
|
return true;
|
|
408
985
|
}
|
|
986
|
+
function writeOutputs(outputs, cwd, label) {
|
|
987
|
+
let written = 0;
|
|
988
|
+
for (const output of outputs) {
|
|
989
|
+
if (writeOutput(output, cwd)) {
|
|
990
|
+
written++;
|
|
991
|
+
console.log(chalk2.dim(` ${output.filePath}`));
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
console.log(chalk2.green(`\u2713 ${label}: ${written} file(s) generated`));
|
|
995
|
+
return written;
|
|
996
|
+
}
|
|
997
|
+
async function promptGenerateOptions(configTeams, configPlatforms) {
|
|
998
|
+
const { mode } = await inquirer2.prompt([
|
|
999
|
+
{
|
|
1000
|
+
type: "list",
|
|
1001
|
+
name: "mode",
|
|
1002
|
+
message: "Generate mode:",
|
|
1003
|
+
choices: [
|
|
1004
|
+
{ name: "Platform configs (agents, skills, references)", value: "platform" },
|
|
1005
|
+
{ name: "Plugin bundle", value: "plugin" }
|
|
1006
|
+
]
|
|
1007
|
+
}
|
|
1008
|
+
]);
|
|
1009
|
+
if (mode === "plugin") {
|
|
1010
|
+
return { scopes: ["plugin"] };
|
|
1011
|
+
}
|
|
1012
|
+
const answers = await inquirer2.prompt([
|
|
1013
|
+
{
|
|
1014
|
+
type: "checkbox",
|
|
1015
|
+
name: "scopes",
|
|
1016
|
+
message: "What to generate:",
|
|
1017
|
+
choices: [
|
|
1018
|
+
{ name: "Agents", value: "agents", checked: true },
|
|
1019
|
+
{ name: "Skills", value: "skills", checked: true },
|
|
1020
|
+
{ name: "References", value: "references", checked: true }
|
|
1021
|
+
]
|
|
1022
|
+
},
|
|
1023
|
+
{
|
|
1024
|
+
type: "checkbox",
|
|
1025
|
+
name: "teams",
|
|
1026
|
+
message: "Team agents:",
|
|
1027
|
+
choices: TEAM_ROLES.map((role) => ({
|
|
1028
|
+
name: role,
|
|
1029
|
+
value: role,
|
|
1030
|
+
checked: configTeams.includes(role)
|
|
1031
|
+
})),
|
|
1032
|
+
validate: (input) => input.length > 0 || "Select at least one team"
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
type: "checkbox",
|
|
1036
|
+
name: "platforms",
|
|
1037
|
+
message: "Target platforms:",
|
|
1038
|
+
choices: PLATFORMS.map((p) => ({
|
|
1039
|
+
name: p,
|
|
1040
|
+
value: p,
|
|
1041
|
+
checked: configPlatforms.includes(p)
|
|
1042
|
+
})),
|
|
1043
|
+
validate: (input) => input.length > 0 || "Select at least one platform"
|
|
1044
|
+
}
|
|
1045
|
+
]);
|
|
1046
|
+
const scopes = answers.scopes.length > 0 ? answers.scopes : ["all"];
|
|
1047
|
+
return {
|
|
1048
|
+
scopes,
|
|
1049
|
+
teams: answers.teams,
|
|
1050
|
+
platforms: answers.platforms
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
409
1053
|
async function runGenerate(cwd = process.cwd(), options = {}) {
|
|
410
1054
|
const config = await loadConfig(cwd);
|
|
411
|
-
const
|
|
412
|
-
|
|
1055
|
+
const hasFlags = options.platform || options.platforms || options.teams || options.scopes && !(options.scopes.length === 1 && options.scopes[0] === "all");
|
|
1056
|
+
if (!hasFlags && process.stdin.isTTY) {
|
|
1057
|
+
const prompted = await promptGenerateOptions(config.teams, config.platforms);
|
|
1058
|
+
options = { ...options, ...prompted };
|
|
1059
|
+
}
|
|
1060
|
+
const effectiveConfig = options.teams ? { ...config, teams: options.teams } : config;
|
|
1061
|
+
const agents = loadAgents(effectiveConfig, cwd);
|
|
1062
|
+
const scopes = options.scopes ?? ["all"];
|
|
1063
|
+
if (scopes.includes("plugin")) {
|
|
1064
|
+
const pluginDir = effectiveConfig.output?.pluginDir ?? ".aigent-team-plugin";
|
|
1065
|
+
const pluginCompiler = new PluginCompiler();
|
|
1066
|
+
const outputs = pluginCompiler.compilePlugin(agents, effectiveConfig, pluginDir);
|
|
1067
|
+
const written = writeOutputs(outputs, cwd, "plugin");
|
|
1068
|
+
console.log(chalk2.bold(`
|
|
1069
|
+
Total: ${written} file(s) generated`));
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
const platforms = options.platform ? [options.platform] : options.platforms ?? effectiveConfig.platforms;
|
|
413
1073
|
const compilers2 = getAllCompilers(platforms);
|
|
414
1074
|
let totalFiles = 0;
|
|
415
1075
|
let totalWarnings = 0;
|
|
416
1076
|
for (const compiler of compilers2) {
|
|
417
|
-
const outputs = compiler.
|
|
1077
|
+
const outputs = compiler.compileWithScope(agents, effectiveConfig, scopes);
|
|
418
1078
|
const validation = compiler.validate(outputs);
|
|
419
1079
|
if (!validation.valid) {
|
|
420
|
-
console.log(
|
|
1080
|
+
console.log(chalk2.red(`
|
|
421
1081
|
\u2717 ${compiler.platform} validation errors:`));
|
|
422
1082
|
for (const error of validation.errors) {
|
|
423
|
-
console.log(
|
|
1083
|
+
console.log(chalk2.red(` - ${error}`));
|
|
424
1084
|
}
|
|
425
1085
|
continue;
|
|
426
1086
|
}
|
|
427
1087
|
for (const warning of validation.warnings) {
|
|
428
|
-
console.log(
|
|
1088
|
+
console.log(chalk2.yellow(` \u26A0 ${warning}`));
|
|
429
1089
|
totalWarnings++;
|
|
430
1090
|
}
|
|
431
|
-
|
|
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;
|
|
1091
|
+
totalFiles += writeOutputs(outputs, cwd, compiler.platform);
|
|
440
1092
|
}
|
|
441
|
-
console.log(
|
|
1093
|
+
console.log(chalk2.bold(`
|
|
442
1094
|
Total: ${totalFiles} file(s) generated`));
|
|
443
1095
|
if (totalWarnings > 0) {
|
|
444
|
-
console.log(
|
|
1096
|
+
console.log(chalk2.yellow(`${totalWarnings} warning(s)`));
|
|
445
1097
|
}
|
|
446
1098
|
}
|
|
447
1099
|
|
|
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
1100
|
// src/cli/validate.ts
|
|
524
1101
|
import { existsSync as existsSync3 } from "fs";
|
|
525
1102
|
import { resolve as resolve4 } from "path";
|
|
@@ -559,18 +1136,358 @@ async function runValidate(cwd = process.cwd()) {
|
|
|
559
1136
|
}
|
|
560
1137
|
}
|
|
561
1138
|
|
|
1139
|
+
// src/cli/install.ts
|
|
1140
|
+
import { writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync5, readFileSync as readFileSync4, cpSync, rmSync } from "fs";
|
|
1141
|
+
import { homedir } from "os";
|
|
1142
|
+
import { resolve as resolve6, dirname as dirname2, join } from "path";
|
|
1143
|
+
import chalk4 from "chalk";
|
|
1144
|
+
|
|
1145
|
+
// src/core/plugin-loader.ts
|
|
1146
|
+
import { readFileSync as readFileSync3, existsSync as existsSync4, readdirSync } from "fs";
|
|
1147
|
+
import { resolve as resolve5, basename } from "path";
|
|
1148
|
+
function loadPlugin(pluginPath) {
|
|
1149
|
+
const absPath = resolve5(pluginPath);
|
|
1150
|
+
const manifestPath = resolve5(absPath, "manifest.json");
|
|
1151
|
+
if (!existsSync4(manifestPath)) {
|
|
1152
|
+
throw new Error(`Plugin manifest not found: ${manifestPath}`);
|
|
1153
|
+
}
|
|
1154
|
+
const manifest = JSON.parse(readFileSync3(manifestPath, "utf-8"));
|
|
1155
|
+
if (!manifest.agents?.length) {
|
|
1156
|
+
throw new Error("Plugin manifest has no agents metadata. Was it generated with aigent-team >= 0.3.0?");
|
|
1157
|
+
}
|
|
1158
|
+
const bundleDir = findBundleDir(absPath, manifest);
|
|
1159
|
+
const agents = [];
|
|
1160
|
+
for (const meta of manifest.agents) {
|
|
1161
|
+
const agentFilePath = resolve5(bundleDir, "agents", `${meta.id}-agent.md`);
|
|
1162
|
+
if (!existsSync4(agentFilePath)) {
|
|
1163
|
+
throw new Error(`Agent file not found: ${agentFilePath}`);
|
|
1164
|
+
}
|
|
1165
|
+
const skillContent = readFileSync3(agentFilePath, "utf-8").trim();
|
|
1166
|
+
const skills = loadSkillFiles(resolve5(bundleDir, "skills", meta.id));
|
|
1167
|
+
const references = loadReferenceFiles(resolve5(bundleDir, "kb", meta.id));
|
|
1168
|
+
const sharedKnowledge = loadSharedKnowledge(resolve5(bundleDir, "kb", "shared"));
|
|
1169
|
+
agents.push({
|
|
1170
|
+
id: meta.id,
|
|
1171
|
+
name: meta.name,
|
|
1172
|
+
description: meta.description,
|
|
1173
|
+
role: meta.role,
|
|
1174
|
+
tools: meta.tools,
|
|
1175
|
+
globs: meta.globs,
|
|
1176
|
+
// The skillContent already contains the assembled index (rules + skill content + catalog).
|
|
1177
|
+
// Set it as skillContent and leave rulesContent/skills empty so assembleSkillIndex()
|
|
1178
|
+
// returns it as-is without double-including rules or catalog.
|
|
1179
|
+
skillContent,
|
|
1180
|
+
rulesContent: "",
|
|
1181
|
+
skills,
|
|
1182
|
+
references,
|
|
1183
|
+
sharedKnowledge,
|
|
1184
|
+
// Unused during install — compilers only need the fields above
|
|
1185
|
+
systemPrompt: "",
|
|
1186
|
+
techStack: { languages: [], frameworks: [], libraries: [], buildTools: [] },
|
|
1187
|
+
conventions: "",
|
|
1188
|
+
reviewChecklist: "",
|
|
1189
|
+
workflows: []
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
return { manifest, agents };
|
|
1193
|
+
}
|
|
1194
|
+
function findBundleDir(absPath, manifest) {
|
|
1195
|
+
const preferred = ["claude-code-plugin", "cursor-ide-plugin", "codex-plugin", "antigravity-plugin"];
|
|
1196
|
+
for (const dir of preferred) {
|
|
1197
|
+
const candidate = resolve5(absPath, dir);
|
|
1198
|
+
if (existsSync4(candidate)) return candidate;
|
|
1199
|
+
}
|
|
1200
|
+
for (const bundle of manifest.bundles ?? []) {
|
|
1201
|
+
const candidate = resolve5(absPath, bundle.directory);
|
|
1202
|
+
if (existsSync4(candidate)) return candidate;
|
|
1203
|
+
}
|
|
1204
|
+
throw new Error(`No platform bundle found in plugin: ${absPath}`);
|
|
1205
|
+
}
|
|
1206
|
+
function loadSkillFiles(dir) {
|
|
1207
|
+
if (!existsSync4(dir)) return [];
|
|
1208
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => {
|
|
1209
|
+
const id = basename(f, ".md");
|
|
1210
|
+
const content = readFileSync3(resolve5(dir, f), "utf-8").trim();
|
|
1211
|
+
return {
|
|
1212
|
+
id,
|
|
1213
|
+
name: id.replace(/-/g, " "),
|
|
1214
|
+
description: "",
|
|
1215
|
+
trigger: "",
|
|
1216
|
+
content
|
|
1217
|
+
};
|
|
1218
|
+
});
|
|
1219
|
+
}
|
|
1220
|
+
function loadReferenceFiles(dir) {
|
|
1221
|
+
if (!existsSync4(dir)) return [];
|
|
1222
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md")).map((f) => {
|
|
1223
|
+
const id = basename(f, ".md");
|
|
1224
|
+
const content = readFileSync3(resolve5(dir, f), "utf-8").trim();
|
|
1225
|
+
return {
|
|
1226
|
+
id,
|
|
1227
|
+
title: id.replace(/-/g, " "),
|
|
1228
|
+
description: "",
|
|
1229
|
+
whenToRead: "",
|
|
1230
|
+
content
|
|
1231
|
+
};
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
function loadSharedKnowledge(dir) {
|
|
1235
|
+
if (!existsSync4(dir)) return [];
|
|
1236
|
+
return readdirSync(dir).filter((f) => f.endsWith(".md")).sort().map((f) => readFileSync3(resolve5(dir, f), "utf-8").trim()).filter(Boolean);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// src/cli/install.ts
|
|
1240
|
+
function readCursorPluginId(cursorIdePluginRoot) {
|
|
1241
|
+
const manifestPath = resolve6(cursorIdePluginRoot, ".cursor-plugin", "plugin.json");
|
|
1242
|
+
if (!existsSync5(manifestPath)) {
|
|
1243
|
+
throw new Error(`Missing ${manifestPath}`);
|
|
1244
|
+
}
|
|
1245
|
+
const raw = JSON.parse(readFileSync4(manifestPath, "utf-8"));
|
|
1246
|
+
if (!raw.name || typeof raw.name !== "string") {
|
|
1247
|
+
throw new Error(`Invalid Cursor plugin manifest: missing "name" in ${manifestPath}`);
|
|
1248
|
+
}
|
|
1249
|
+
return raw.name;
|
|
1250
|
+
}
|
|
1251
|
+
function installCursorUserPlugin(cursorIdePluginSource, force) {
|
|
1252
|
+
const pluginId = readCursorPluginId(cursorIdePluginSource);
|
|
1253
|
+
const localRoot = join(homedir(), ".cursor", "plugins", "local");
|
|
1254
|
+
const dest = join(localRoot, pluginId);
|
|
1255
|
+
if (existsSync5(dest) && !force) {
|
|
1256
|
+
throw new Error(
|
|
1257
|
+
`Cursor user plugin already exists: ${dest}
|
|
1258
|
+
Use --force to replace, or remove that folder first.`
|
|
1259
|
+
);
|
|
1260
|
+
}
|
|
1261
|
+
mkdirSync3(localRoot, { recursive: true });
|
|
1262
|
+
if (existsSync5(dest)) {
|
|
1263
|
+
rmSync(dest, { recursive: true, force: true });
|
|
1264
|
+
}
|
|
1265
|
+
cpSync(cursorIdePluginSource, dest, { recursive: true });
|
|
1266
|
+
return dest;
|
|
1267
|
+
}
|
|
1268
|
+
function writeInstallOutput(output, cwd, force) {
|
|
1269
|
+
const fullPath = resolve6(cwd, output.filePath);
|
|
1270
|
+
const dir = dirname2(fullPath);
|
|
1271
|
+
if (!force && existsSync5(fullPath)) {
|
|
1272
|
+
return false;
|
|
1273
|
+
}
|
|
1274
|
+
mkdirSync3(dir, { recursive: true });
|
|
1275
|
+
writeFileSync3(fullPath, output.content);
|
|
1276
|
+
return true;
|
|
1277
|
+
}
|
|
1278
|
+
async function runInstall(pluginPath, cwd = process.cwd(), options = {}) {
|
|
1279
|
+
const absPluginPath = resolve6(cwd, pluginPath);
|
|
1280
|
+
console.log(chalk4.dim(`Loading plugin from ${absPluginPath}...`));
|
|
1281
|
+
const { manifest, agents } = loadPlugin(absPluginPath);
|
|
1282
|
+
console.log(chalk4.bold(`Plugin: ${manifest.name} v${manifest.version}`));
|
|
1283
|
+
console.log(chalk4.dim(` ${manifest.agents.length} agent(s), ${manifest.files.skills} skill(s), ${manifest.files.references} reference(s)`));
|
|
1284
|
+
let platforms;
|
|
1285
|
+
if (options.platform) {
|
|
1286
|
+
platforms = [options.platform];
|
|
1287
|
+
} else if (configExists(cwd)) {
|
|
1288
|
+
const config2 = await loadConfig(cwd);
|
|
1289
|
+
platforms = config2.platforms;
|
|
1290
|
+
} else {
|
|
1291
|
+
platforms = manifest.platforms;
|
|
1292
|
+
}
|
|
1293
|
+
const config = configExists(cwd) ? await loadConfig(cwd) : {
|
|
1294
|
+
projectName: manifest.projectName,
|
|
1295
|
+
platforms,
|
|
1296
|
+
teams: manifest.roles
|
|
1297
|
+
};
|
|
1298
|
+
const compilers2 = getAllCompilers(platforms);
|
|
1299
|
+
const allWrittenFiles = [];
|
|
1300
|
+
let totalFiles = 0;
|
|
1301
|
+
let skipped = 0;
|
|
1302
|
+
for (const compiler of compilers2) {
|
|
1303
|
+
if (options.cursorUserPlugin && compiler.platform === "cursor") {
|
|
1304
|
+
continue;
|
|
1305
|
+
}
|
|
1306
|
+
const outputs = compiler.compileWithScope(agents, config, ["all"]);
|
|
1307
|
+
const validation = compiler.validate(outputs);
|
|
1308
|
+
if (!validation.valid) {
|
|
1309
|
+
console.log(chalk4.red(`
|
|
1310
|
+
\u2717 ${compiler.platform} validation errors:`));
|
|
1311
|
+
for (const error of validation.errors) {
|
|
1312
|
+
console.log(chalk4.red(` - ${error}`));
|
|
1313
|
+
}
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
for (const warning of validation.warnings) {
|
|
1317
|
+
console.log(chalk4.yellow(` \u26A0 ${warning}`));
|
|
1318
|
+
}
|
|
1319
|
+
let written = 0;
|
|
1320
|
+
for (const output of outputs) {
|
|
1321
|
+
if (writeInstallOutput(output, cwd, !!options.force)) {
|
|
1322
|
+
written++;
|
|
1323
|
+
allWrittenFiles.push(output.filePath);
|
|
1324
|
+
console.log(chalk4.dim(` ${output.filePath}`));
|
|
1325
|
+
} else {
|
|
1326
|
+
skipped++;
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
console.log(chalk4.green(`\u2713 ${compiler.platform}: ${written} file(s) installed`));
|
|
1330
|
+
totalFiles += written;
|
|
1331
|
+
}
|
|
1332
|
+
let cursorUserPluginPath;
|
|
1333
|
+
const cursorIdeBundle = resolve6(absPluginPath, "cursor-ide-plugin");
|
|
1334
|
+
const shouldInstallCursorUser = !!options.cursorUserPlugin && (!options.platform || options.platform === "cursor") && platforms.includes("cursor");
|
|
1335
|
+
if (shouldInstallCursorUser) {
|
|
1336
|
+
if (!existsSync5(cursorIdeBundle)) {
|
|
1337
|
+
console.log(
|
|
1338
|
+
chalk4.red(
|
|
1339
|
+
`
|
|
1340
|
+
\u2717 cursor-ide-plugin/ not found under ${absPluginPath}.
|
|
1341
|
+
Run: npx aigent-team generate --scope plugin`
|
|
1342
|
+
)
|
|
1343
|
+
);
|
|
1344
|
+
} else {
|
|
1345
|
+
try {
|
|
1346
|
+
cursorUserPluginPath = installCursorUserPlugin(cursorIdeBundle, !!options.force);
|
|
1347
|
+
console.log(chalk4.green(`\u2713 cursor (user plugin): ${cursorUserPluginPath}`));
|
|
1348
|
+
} catch (e) {
|
|
1349
|
+
console.log(chalk4.red(`
|
|
1350
|
+
\u2717 Cursor user plugin install failed: ${e.message}`));
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
const recordDir = resolve6(cwd, ".aigent-team", "installed");
|
|
1355
|
+
mkdirSync3(recordDir, { recursive: true });
|
|
1356
|
+
const record = {
|
|
1357
|
+
name: manifest.name,
|
|
1358
|
+
version: manifest.version,
|
|
1359
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1360
|
+
pluginPath: absPluginPath,
|
|
1361
|
+
files: allWrittenFiles,
|
|
1362
|
+
...cursorUserPluginPath ? { cursorUserPluginPath } : {}
|
|
1363
|
+
};
|
|
1364
|
+
writeFileSync3(
|
|
1365
|
+
resolve6(recordDir, `${manifest.name}.json`),
|
|
1366
|
+
JSON.stringify(record, null, 2) + "\n"
|
|
1367
|
+
);
|
|
1368
|
+
console.log(chalk4.bold(`
|
|
1369
|
+
Total: ${totalFiles} file(s) installed`));
|
|
1370
|
+
if (skipped > 0) {
|
|
1371
|
+
console.log(chalk4.yellow(`${skipped} file(s) skipped (already exist, use --force to overwrite)`));
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// src/cli/uninstall.ts
|
|
1376
|
+
import { unlinkSync, existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync2, rmdirSync, rmSync as rmSync2 } from "fs";
|
|
1377
|
+
import { resolve as resolve7, dirname as dirname3 } from "path";
|
|
1378
|
+
import chalk5 from "chalk";
|
|
1379
|
+
async function runUninstall(pluginName, cwd = process.cwd()) {
|
|
1380
|
+
const recordPath = resolve7(cwd, ".aigent-team", "installed", `${pluginName}.json`);
|
|
1381
|
+
if (!existsSync6(recordPath)) {
|
|
1382
|
+
const installedDir = resolve7(cwd, ".aigent-team", "installed");
|
|
1383
|
+
if (existsSync6(installedDir)) {
|
|
1384
|
+
const installed = readdirSync2(installedDir).filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
|
|
1385
|
+
if (installed.length > 0) {
|
|
1386
|
+
console.log(chalk5.red(`Plugin "${pluginName}" is not installed.`));
|
|
1387
|
+
console.log(chalk5.dim(`Installed plugins: ${installed.join(", ")}`));
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
console.log(chalk5.red(`No installed plugins found.`));
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
const record = JSON.parse(readFileSync5(recordPath, "utf-8"));
|
|
1395
|
+
console.log(chalk5.bold(`Uninstalling: ${record.name} v${record.version}`));
|
|
1396
|
+
if (record.cursorUserPluginPath && existsSync6(record.cursorUserPluginPath)) {
|
|
1397
|
+
rmSync2(record.cursorUserPluginPath, { recursive: true, force: true });
|
|
1398
|
+
console.log(chalk5.dim(` \u2717 ${record.cursorUserPluginPath} (Cursor user plugin)`));
|
|
1399
|
+
}
|
|
1400
|
+
let removed = 0;
|
|
1401
|
+
let missing = 0;
|
|
1402
|
+
for (const filePath of record.files) {
|
|
1403
|
+
const fullPath = resolve7(cwd, filePath);
|
|
1404
|
+
if (existsSync6(fullPath)) {
|
|
1405
|
+
unlinkSync(fullPath);
|
|
1406
|
+
removed++;
|
|
1407
|
+
console.log(chalk5.dim(` \u2717 ${filePath}`));
|
|
1408
|
+
tryRemoveEmptyDir(dirname3(fullPath));
|
|
1409
|
+
} else {
|
|
1410
|
+
missing++;
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
unlinkSync(recordPath);
|
|
1414
|
+
console.log(chalk5.bold(`
|
|
1415
|
+
Removed: ${removed} file(s)`));
|
|
1416
|
+
if (missing > 0) {
|
|
1417
|
+
console.log(chalk5.yellow(`${missing} file(s) already missing`));
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
function tryRemoveEmptyDir(dir) {
|
|
1421
|
+
try {
|
|
1422
|
+
const entries = readdirSync2(dir);
|
|
1423
|
+
if (entries.length === 0) {
|
|
1424
|
+
rmdirSync(dir);
|
|
1425
|
+
tryRemoveEmptyDir(dirname3(dir));
|
|
1426
|
+
}
|
|
1427
|
+
} catch {
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
|
|
562
1431
|
// bin/cli.ts
|
|
563
1432
|
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.
|
|
1433
|
+
program.name("aigent-team").description("Cross-platform AI agent team plugin for Claude Code, Cursor, Codex, and Antigravity").version("0.2.0");
|
|
565
1434
|
program.command("init").description("Initialize aigent-team in your project (interactive)").action(async () => {
|
|
566
1435
|
await runInit(process.cwd());
|
|
567
1436
|
});
|
|
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) => {
|
|
1437
|
+
program.command("generate").description("Generate platform-specific config files from aigent-team config").option("-p, --platform <platform>", "Generate for a specific platform only").option("-s, --scope <scopes>", "Output scope(s), comma-separated: all | agents | skills | references | plugin", "all").option("-t, --team <teams>", "Team roles to generate, comma-separated (overrides config)").action(async (options) => {
|
|
1438
|
+
if (options.platform && !PLATFORMS.includes(options.platform)) {
|
|
1439
|
+
console.log(chalk6.red(`Unknown platform: ${options.platform}. Valid: ${PLATFORMS.join(", ")}`));
|
|
1440
|
+
process.exit(1);
|
|
1441
|
+
}
|
|
1442
|
+
const scopes = options.scope.split(",");
|
|
1443
|
+
for (const s of scopes) {
|
|
1444
|
+
if (!GENERATE_SCOPES.includes(s)) {
|
|
1445
|
+
console.log(chalk6.red(`Unknown scope: ${s}. Valid: ${GENERATE_SCOPES.join(", ")}`));
|
|
1446
|
+
process.exit(1);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
if (scopes.includes("plugin") && scopes.length > 1) {
|
|
1450
|
+
console.log(chalk6.red(`Scope 'plugin' is exclusive and cannot be combined with other scopes.`));
|
|
1451
|
+
process.exit(1);
|
|
1452
|
+
}
|
|
1453
|
+
if (scopes.includes("all") && scopes.length > 1) {
|
|
1454
|
+
console.log(chalk6.red(`Scope 'all' is exclusive and cannot be combined with other scopes.`));
|
|
1455
|
+
process.exit(1);
|
|
1456
|
+
}
|
|
1457
|
+
let teams;
|
|
1458
|
+
if (options.team) {
|
|
1459
|
+
teams = options.team.split(",");
|
|
1460
|
+
for (const t of teams) {
|
|
1461
|
+
if (!TEAM_ROLES.includes(t)) {
|
|
1462
|
+
console.log(chalk6.red(`Unknown team role: ${t}. Valid: ${TEAM_ROLES.join(", ")}`));
|
|
1463
|
+
process.exit(1);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
}
|
|
569
1467
|
await runGenerate(process.cwd(), {
|
|
570
|
-
platform: options.platform
|
|
1468
|
+
platform: options.platform,
|
|
1469
|
+
scopes,
|
|
1470
|
+
teams
|
|
571
1471
|
});
|
|
572
1472
|
});
|
|
573
1473
|
program.command("validate").description("Validate generated config files against platform constraints").action(async () => {
|
|
574
1474
|
await runValidate(process.cwd());
|
|
575
1475
|
});
|
|
1476
|
+
program.command("install").description("Install a plugin bundle into the current project").argument("<plugin-path>", "Path to plugin directory (containing manifest.json)").option("-p, --platform <platform>", "Install for a specific platform only").option("-f, --force", "Overwrite existing files").option(
|
|
1477
|
+
"--cursor-user-plugin",
|
|
1478
|
+
"Install Cursor IDE bundle from plugin cursor-ide-plugin/ to ~/.cursor/plugins/local/ (see cursor.com/docs/plugins)"
|
|
1479
|
+
).action(async (pluginPath, options) => {
|
|
1480
|
+
if (options.platform && !PLATFORMS.includes(options.platform)) {
|
|
1481
|
+
console.log(chalk6.red(`Unknown platform: ${options.platform}. Valid: ${PLATFORMS.join(", ")}`));
|
|
1482
|
+
process.exit(1);
|
|
1483
|
+
}
|
|
1484
|
+
await runInstall(pluginPath, process.cwd(), {
|
|
1485
|
+
platform: options.platform,
|
|
1486
|
+
force: options.force,
|
|
1487
|
+
cursorUserPlugin: options.cursorUserPlugin
|
|
1488
|
+
});
|
|
1489
|
+
});
|
|
1490
|
+
program.command("uninstall").description("Uninstall a previously installed plugin").argument("<plugin-name>", "Name of the plugin to uninstall").action(async (pluginName) => {
|
|
1491
|
+
await runUninstall(pluginName, process.cwd());
|
|
1492
|
+
});
|
|
576
1493
|
program.parse();
|