aigent-team 0.2.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 +103 -7
- package/dist/{chunk-U3NGK2UZ.js → chunk-RH4B2QFX.js} +11 -1
- package/dist/cli.js +1064 -192
- package/dist/index.d.ts +5 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,23 +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,
|
|
6
9
|
assembleSkill,
|
|
7
10
|
assembleSkillIndex,
|
|
8
11
|
configExists,
|
|
9
12
|
loadAgents,
|
|
10
13
|
loadConfig
|
|
11
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-RH4B2QFX.js";
|
|
12
15
|
|
|
13
16
|
// bin/cli.ts
|
|
14
17
|
import { Command } from "commander";
|
|
18
|
+
import chalk6 from "chalk";
|
|
15
19
|
|
|
16
20
|
// src/cli/init.ts
|
|
17
|
-
import { writeFileSync
|
|
18
|
-
import { resolve as
|
|
21
|
+
import { writeFileSync } from "fs";
|
|
22
|
+
import { resolve as resolve2 } from "path";
|
|
19
23
|
import inquirer from "inquirer";
|
|
20
|
-
import
|
|
24
|
+
import chalk from "chalk";
|
|
21
25
|
|
|
22
26
|
// src/detectors/platform-detector.ts
|
|
23
27
|
import { execSync } from "child_process";
|
|
@@ -65,13 +69,132 @@ function detectPlatforms(cwd = process.cwd()) {
|
|
|
65
69
|
return results;
|
|
66
70
|
}
|
|
67
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
|
+
|
|
68
145
|
// src/cli/generate.ts
|
|
69
|
-
import { writeFileSync, mkdirSync, existsSync as existsSync2, readFileSync } from "fs";
|
|
70
|
-
import { resolve as
|
|
71
|
-
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";
|
|
72
150
|
|
|
73
151
|
// src/compilers/base.compiler.ts
|
|
74
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 ----
|
|
75
198
|
/**
|
|
76
199
|
* Compile reference files for an agent into a given directory.
|
|
77
200
|
* Returns CompiledOutput[] for each reference file.
|
|
@@ -118,6 +241,31 @@ var BaseCompiler = class {
|
|
|
118
241
|
var ClaudeCodeCompiler = class extends BaseCompiler {
|
|
119
242
|
platform = "claude-code";
|
|
120
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) {
|
|
121
269
|
const outputs = [];
|
|
122
270
|
for (const agent of agents) {
|
|
123
271
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -135,37 +283,94 @@ ${body}
|
|
|
135
283
|
content,
|
|
136
284
|
overwriteStrategy: "replace"
|
|
137
285
|
});
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
286
|
+
}
|
|
287
|
+
return outputs;
|
|
288
|
+
}
|
|
289
|
+
compileAllSkills(agents) {
|
|
290
|
+
const outputs = [];
|
|
291
|
+
for (const agent of agents) {
|
|
292
|
+
outputs.push(...this.compileSkills(
|
|
144
293
|
agent,
|
|
145
294
|
`.claude/agents/${agent.id}-agent/skills`
|
|
146
|
-
);
|
|
147
|
-
|
|
295
|
+
));
|
|
296
|
+
}
|
|
297
|
+
return outputs;
|
|
298
|
+
}
|
|
299
|
+
compileAllReferences(agents) {
|
|
300
|
+
const outputs = [];
|
|
301
|
+
for (const agent of agents) {
|
|
302
|
+
outputs.push(...this.compileReferences(
|
|
303
|
+
agent,
|
|
304
|
+
`.claude/agents/${agent.id}-agent/references`
|
|
305
|
+
));
|
|
148
306
|
}
|
|
307
|
+
return outputs;
|
|
308
|
+
}
|
|
309
|
+
compilePluginBundle(agents, config, rootDir) {
|
|
310
|
+
const outputs = [];
|
|
149
311
|
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
150
|
-
const claudeMd = [
|
|
151
|
-
`# CLAUDE.md`,
|
|
152
|
-
``,
|
|
153
|
-
`This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.`,
|
|
154
|
-
``,
|
|
155
|
-
`## Agent Team`,
|
|
156
|
-
``,
|
|
157
|
-
`This project uses aigent-team. The following specialized agents are available:`,
|
|
158
|
-
``,
|
|
159
|
-
agentList,
|
|
160
|
-
``,
|
|
161
|
-
`Use the appropriate agent for your task by invoking it from the .claude/agents/ directory.`,
|
|
162
|
-
``
|
|
163
|
-
].join("\n");
|
|
164
312
|
outputs.push({
|
|
165
|
-
filePath:
|
|
166
|
-
content:
|
|
167
|
-
|
|
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"
|
|
168
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
|
+
}
|
|
169
374
|
return outputs;
|
|
170
375
|
}
|
|
171
376
|
validate(outputs) {
|
|
@@ -184,10 +389,38 @@ ${body}
|
|
|
184
389
|
}
|
|
185
390
|
};
|
|
186
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
|
+
|
|
187
401
|
// src/compilers/cursor.compiler.ts
|
|
188
402
|
var CursorCompiler = class extends BaseCompiler {
|
|
189
403
|
platform = "cursor";
|
|
190
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) {
|
|
191
424
|
const outputs = [];
|
|
192
425
|
for (const agent of agents) {
|
|
193
426
|
const globs = agent.globs?.length ? agent.globs.join(", ") : void 0;
|
|
@@ -209,41 +442,74 @@ ${body}
|
|
|
209
442
|
content,
|
|
210
443
|
overwriteStrategy: "replace"
|
|
211
444
|
});
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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}
|
|
222
462
|
|
|
223
|
-
${
|
|
463
|
+
${skill.content}
|
|
224
464
|
`,
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
465
|
+
overwriteStrategy: "replace"
|
|
466
|
+
});
|
|
228
467
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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}
|
|
239
485
|
|
|
240
|
-
${
|
|
486
|
+
${ref.content}
|
|
241
487
|
`,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
488
|
+
overwriteStrategy: "replace"
|
|
489
|
+
});
|
|
245
490
|
}
|
|
246
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
|
+
});
|
|
247
513
|
const sharedKnowledge = agents.flatMap((a) => a.sharedKnowledge).filter((v, i, arr) => arr.indexOf(v) === i && v).join("\n\n---\n\n");
|
|
248
514
|
if (sharedKnowledge) {
|
|
249
515
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -251,7 +517,7 @@ ${skill.content}
|
|
|
251
517
|
alwaysApply: true
|
|
252
518
|
});
|
|
253
519
|
outputs.push({
|
|
254
|
-
filePath:
|
|
520
|
+
filePath: `${rootDir}/rules/shared-conventions.mdc`,
|
|
255
521
|
content: `${frontmatter}
|
|
256
522
|
|
|
257
523
|
${sharedKnowledge}
|
|
@@ -259,6 +525,62 @@ ${sharedKnowledge}
|
|
|
259
525
|
overwriteStrategy: "replace"
|
|
260
526
|
});
|
|
261
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
|
+
}
|
|
262
584
|
return outputs;
|
|
263
585
|
}
|
|
264
586
|
validate(outputs) {
|
|
@@ -280,7 +602,9 @@ ${sharedKnowledge}
|
|
|
280
602
|
var CodexCompiler = class extends BaseCompiler {
|
|
281
603
|
platform = "codex";
|
|
282
604
|
compile(agents, config) {
|
|
283
|
-
|
|
605
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
606
|
+
}
|
|
607
|
+
compileHubFile(agents, _config) {
|
|
284
608
|
const sections = agents.map((agent) => {
|
|
285
609
|
const body = assembleSkillIndex(agent);
|
|
286
610
|
return `## ${agent.name} (${agent.id})
|
|
@@ -299,11 +623,14 @@ ${body}`;
|
|
|
299
623
|
|
|
300
624
|
${sharedKnowledge}` : ""
|
|
301
625
|
].filter(Boolean).join("\n\n");
|
|
302
|
-
|
|
626
|
+
return [{
|
|
303
627
|
filePath: "AGENTS.md",
|
|
304
628
|
content: agentsMd + "\n",
|
|
305
629
|
overwriteStrategy: "replace"
|
|
306
|
-
}
|
|
630
|
+
}];
|
|
631
|
+
}
|
|
632
|
+
compileAgentIndexes(agents, _config) {
|
|
633
|
+
const outputs = [];
|
|
307
634
|
for (const agent of agents) {
|
|
308
635
|
const frontmatter = this.formatFrontmatter({
|
|
309
636
|
nickname_candidates: [agent.id, agent.role],
|
|
@@ -319,32 +646,104 @@ ${body}
|
|
|
319
646
|
content,
|
|
320
647
|
overwriteStrategy: "replace"
|
|
321
648
|
});
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
649
|
+
}
|
|
650
|
+
return outputs;
|
|
651
|
+
}
|
|
652
|
+
compileAllSkills(agents) {
|
|
653
|
+
const outputs = [];
|
|
654
|
+
for (const agent of agents) {
|
|
655
|
+
outputs.push(...this.compileSkills(
|
|
328
656
|
agent,
|
|
329
657
|
`.codex/agents/${agent.id}-agent/skills`
|
|
330
|
-
);
|
|
331
|
-
outputs.push(...skills);
|
|
658
|
+
));
|
|
332
659
|
}
|
|
333
660
|
return outputs;
|
|
334
661
|
}
|
|
335
|
-
|
|
336
|
-
const
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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
|
+
));
|
|
341
669
|
}
|
|
342
|
-
return
|
|
670
|
+
return outputs;
|
|
343
671
|
}
|
|
344
|
-
|
|
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})
|
|
345
677
|
|
|
346
|
-
|
|
347
|
-
|
|
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 = {
|
|
348
747
|
Read: "read_file",
|
|
349
748
|
Write: "str_replace_editor",
|
|
350
749
|
Edit: "str_replace_editor",
|
|
@@ -355,7 +754,9 @@ var TOOL_MAP = {
|
|
|
355
754
|
var AntigravityCompiler = class extends BaseCompiler {
|
|
356
755
|
platform = "antigravity";
|
|
357
756
|
compile(agents, config) {
|
|
358
|
-
|
|
757
|
+
return this.compileWithScope(agents, config, ["all"]);
|
|
758
|
+
}
|
|
759
|
+
compileHubFile(agents, _config) {
|
|
359
760
|
const agentList = agents.map((a) => `- **${a.name}** (\`${a.id}\`): ${a.description.trim().split("\n")[0]}`).join("\n");
|
|
360
761
|
const geminiMd = [
|
|
361
762
|
`# Antigravity Configuration`,
|
|
@@ -368,11 +769,14 @@ var AntigravityCompiler = class extends BaseCompiler {
|
|
|
368
769
|
`Use the appropriate agent skill for team-specific tasks.`,
|
|
369
770
|
``
|
|
370
771
|
].join("\n");
|
|
371
|
-
|
|
772
|
+
return [{
|
|
372
773
|
filePath: "GEMINI.md",
|
|
373
774
|
content: geminiMd,
|
|
374
775
|
overwriteStrategy: "replace"
|
|
375
|
-
}
|
|
776
|
+
}];
|
|
777
|
+
}
|
|
778
|
+
compileAgentIndexes(agents, _config) {
|
|
779
|
+
const outputs = [];
|
|
376
780
|
for (const agent of agents) {
|
|
377
781
|
const allowedTools = agent.tools.allowed.map((t) => TOOL_MAP[t] || t.toLowerCase()).filter((v, i, arr) => arr.indexOf(v) === i);
|
|
378
782
|
const frontmatter = this.formatFrontmatter({
|
|
@@ -390,16 +794,91 @@ ${body}
|
|
|
390
794
|
content,
|
|
391
795
|
overwriteStrategy: "replace"
|
|
392
796
|
});
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
797
|
+
}
|
|
798
|
+
return outputs;
|
|
799
|
+
}
|
|
800
|
+
compileAllSkills(agents) {
|
|
801
|
+
const outputs = [];
|
|
802
|
+
for (const agent of agents) {
|
|
803
|
+
outputs.push(...this.compileSkills(
|
|
399
804
|
agent,
|
|
400
805
|
`.agents/skills/${agent.id}-agent/skills`
|
|
401
|
-
);
|
|
402
|
-
|
|
806
|
+
));
|
|
807
|
+
}
|
|
808
|
+
return outputs;
|
|
809
|
+
}
|
|
810
|
+
compileAllReferences(agents) {
|
|
811
|
+
const outputs = [];
|
|
812
|
+
for (const agent of agents) {
|
|
813
|
+
outputs.push(...this.compileReferences(
|
|
814
|
+
agent,
|
|
815
|
+
`.agents/skills/${agent.id}-agent/references`
|
|
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
|
+
});
|
|
403
882
|
}
|
|
404
883
|
return outputs;
|
|
405
884
|
}
|
|
@@ -428,13 +907,66 @@ var compilers = {
|
|
|
428
907
|
codex: () => new CodexCompiler(),
|
|
429
908
|
antigravity: () => new AntigravityCompiler()
|
|
430
909
|
};
|
|
910
|
+
function getCompiler(platform) {
|
|
911
|
+
return compilers[platform]();
|
|
912
|
+
}
|
|
431
913
|
function getAllCompilers(platforms) {
|
|
432
914
|
return platforms.map((p) => compilers[p]());
|
|
433
915
|
}
|
|
434
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
|
+
|
|
435
967
|
// src/cli/generate.ts
|
|
436
968
|
function writeOutput(output, cwd) {
|
|
437
|
-
const fullPath =
|
|
969
|
+
const fullPath = resolve3(cwd, output.filePath);
|
|
438
970
|
const dir = dirname(fullPath);
|
|
439
971
|
if (output.overwriteStrategy === "skip-if-exists" && existsSync2(fullPath)) {
|
|
440
972
|
return false;
|
|
@@ -442,129 +974,129 @@ function writeOutput(output, cwd) {
|
|
|
442
974
|
if (output.overwriteStrategy === "merge" && existsSync2(fullPath)) {
|
|
443
975
|
const existing = readFileSync(fullPath, "utf-8");
|
|
444
976
|
if (!existing.includes("## Agent Team")) {
|
|
445
|
-
|
|
977
|
+
writeFileSync2(fullPath, existing + "\n" + output.content);
|
|
446
978
|
return true;
|
|
447
979
|
}
|
|
448
980
|
return false;
|
|
449
981
|
}
|
|
450
|
-
|
|
451
|
-
|
|
982
|
+
mkdirSync2(dir, { recursive: true });
|
|
983
|
+
writeFileSync2(fullPath, output.content);
|
|
452
984
|
return true;
|
|
453
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
|
+
}
|
|
454
1053
|
async function runGenerate(cwd = process.cwd(), options = {}) {
|
|
455
1054
|
const config = await loadConfig(cwd);
|
|
456
|
-
const
|
|
457
|
-
|
|
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;
|
|
458
1073
|
const compilers2 = getAllCompilers(platforms);
|
|
459
1074
|
let totalFiles = 0;
|
|
460
1075
|
let totalWarnings = 0;
|
|
461
1076
|
for (const compiler of compilers2) {
|
|
462
|
-
const outputs = compiler.
|
|
1077
|
+
const outputs = compiler.compileWithScope(agents, effectiveConfig, scopes);
|
|
463
1078
|
const validation = compiler.validate(outputs);
|
|
464
1079
|
if (!validation.valid) {
|
|
465
|
-
console.log(
|
|
1080
|
+
console.log(chalk2.red(`
|
|
466
1081
|
\u2717 ${compiler.platform} validation errors:`));
|
|
467
1082
|
for (const error of validation.errors) {
|
|
468
|
-
console.log(
|
|
1083
|
+
console.log(chalk2.red(` - ${error}`));
|
|
469
1084
|
}
|
|
470
1085
|
continue;
|
|
471
1086
|
}
|
|
472
1087
|
for (const warning of validation.warnings) {
|
|
473
|
-
console.log(
|
|
1088
|
+
console.log(chalk2.yellow(` \u26A0 ${warning}`));
|
|
474
1089
|
totalWarnings++;
|
|
475
1090
|
}
|
|
476
|
-
|
|
477
|
-
for (const output of outputs) {
|
|
478
|
-
if (writeOutput(output, cwd)) {
|
|
479
|
-
written++;
|
|
480
|
-
console.log(chalk.dim(` ${output.filePath}`));
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
console.log(chalk.green(`\u2713 ${compiler.platform}: ${written} file(s) generated`));
|
|
484
|
-
totalFiles += written;
|
|
1091
|
+
totalFiles += writeOutputs(outputs, cwd, compiler.platform);
|
|
485
1092
|
}
|
|
486
|
-
console.log(
|
|
1093
|
+
console.log(chalk2.bold(`
|
|
487
1094
|
Total: ${totalFiles} file(s) generated`));
|
|
488
1095
|
if (totalWarnings > 0) {
|
|
489
|
-
console.log(
|
|
1096
|
+
console.log(chalk2.yellow(`${totalWarnings} warning(s)`));
|
|
490
1097
|
}
|
|
491
1098
|
}
|
|
492
1099
|
|
|
493
|
-
// src/cli/init.ts
|
|
494
|
-
async function runInit(cwd = process.cwd()) {
|
|
495
|
-
console.log(chalk2.bold("\n\u{1F916} aigent-team init\n"));
|
|
496
|
-
if (configExists(cwd)) {
|
|
497
|
-
const { overwrite } = await inquirer.prompt([
|
|
498
|
-
{
|
|
499
|
-
type: "confirm",
|
|
500
|
-
name: "overwrite",
|
|
501
|
-
message: "aigent-team.config.json already exists. Overwrite?",
|
|
502
|
-
default: false
|
|
503
|
-
}
|
|
504
|
-
]);
|
|
505
|
-
if (!overwrite) {
|
|
506
|
-
console.log(chalk2.yellow("Aborted."));
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
console.log(chalk2.dim("Detecting installed AI tools..."));
|
|
511
|
-
const detections = detectPlatforms(cwd);
|
|
512
|
-
const detectedPlatforms = detections.filter((d) => d.detected);
|
|
513
|
-
if (detectedPlatforms.length > 0) {
|
|
514
|
-
console.log(chalk2.green(`Found: ${detectedPlatforms.map((d) => d.platform).join(", ")}`));
|
|
515
|
-
} else {
|
|
516
|
-
console.log(chalk2.dim("No AI tools detected. You can still select platforms manually."));
|
|
517
|
-
}
|
|
518
|
-
const answers = await inquirer.prompt([
|
|
519
|
-
{
|
|
520
|
-
type: "input",
|
|
521
|
-
name: "projectName",
|
|
522
|
-
message: "Project name:",
|
|
523
|
-
default: cwd.split("/").pop()
|
|
524
|
-
},
|
|
525
|
-
{
|
|
526
|
-
type: "checkbox",
|
|
527
|
-
name: "platforms",
|
|
528
|
-
message: "Target platforms:",
|
|
529
|
-
choices: PLATFORMS.map((p) => ({
|
|
530
|
-
name: p,
|
|
531
|
-
checked: detections.find((d) => d.platform === p)?.detected ?? false
|
|
532
|
-
})),
|
|
533
|
-
validate: (input) => input.length > 0 || "Select at least one platform"
|
|
534
|
-
},
|
|
535
|
-
{
|
|
536
|
-
type: "checkbox",
|
|
537
|
-
name: "teams",
|
|
538
|
-
message: "Team agents to enable:",
|
|
539
|
-
choices: [
|
|
540
|
-
{ name: "Lead (Tech Lead / Orchestrator)", value: "lead", checked: true },
|
|
541
|
-
{ name: "BA (Business Analyst)", value: "ba", checked: true },
|
|
542
|
-
{ name: "FE (Frontend)", value: "fe", checked: true },
|
|
543
|
-
{ name: "BE (Backend)", value: "be", checked: true },
|
|
544
|
-
{ name: "QA (Testing)", value: "qa", checked: true },
|
|
545
|
-
{ name: "DevOps (Infrastructure)", value: "devops", checked: true }
|
|
546
|
-
],
|
|
547
|
-
validate: (input) => input.length > 0 || "Select at least one team"
|
|
548
|
-
}
|
|
549
|
-
]);
|
|
550
|
-
const config = {
|
|
551
|
-
projectName: answers.projectName,
|
|
552
|
-
platforms: answers.platforms,
|
|
553
|
-
teams: answers.teams
|
|
554
|
-
};
|
|
555
|
-
const configPath = resolve3(cwd, "aigent-team.config.json");
|
|
556
|
-
writeFileSync2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
557
|
-
console.log(chalk2.green(`
|
|
558
|
-
\u2713 Created ${configPath}`));
|
|
559
|
-
console.log(chalk2.dim("\nGenerating platform configs..."));
|
|
560
|
-
await runGenerate(cwd);
|
|
561
|
-
console.log(chalk2.bold.green("\n\u2705 aigent-team initialized successfully!\n"));
|
|
562
|
-
console.log(chalk2.dim("Next steps:"));
|
|
563
|
-
console.log(chalk2.dim(" - Edit aigent-team.config.json to customize agents"));
|
|
564
|
-
console.log(chalk2.dim(" - Run `aigent-team generate` after making changes"));
|
|
565
|
-
console.log(chalk2.dim(" - Add .aigent-team/teams/<role>/ for local overrides\n"));
|
|
566
|
-
}
|
|
567
|
-
|
|
568
1100
|
// src/cli/validate.ts
|
|
569
1101
|
import { existsSync as existsSync3 } from "fs";
|
|
570
1102
|
import { resolve as resolve4 } from "path";
|
|
@@ -604,18 +1136,358 @@ async function runValidate(cwd = process.cwd()) {
|
|
|
604
1136
|
}
|
|
605
1137
|
}
|
|
606
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
|
+
|
|
607
1431
|
// bin/cli.ts
|
|
608
1432
|
var program = new Command();
|
|
609
|
-
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");
|
|
610
1434
|
program.command("init").description("Initialize aigent-team in your project (interactive)").action(async () => {
|
|
611
1435
|
await runInit(process.cwd());
|
|
612
1436
|
});
|
|
613
|
-
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
|
+
}
|
|
614
1467
|
await runGenerate(process.cwd(), {
|
|
615
|
-
platform: options.platform
|
|
1468
|
+
platform: options.platform,
|
|
1469
|
+
scopes,
|
|
1470
|
+
teams
|
|
616
1471
|
});
|
|
617
1472
|
});
|
|
618
1473
|
program.command("validate").description("Validate generated config files against platform constraints").action(async () => {
|
|
619
1474
|
await runValidate(process.cwd());
|
|
620
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
|
+
});
|
|
621
1493
|
program.parse();
|