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/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-N3RYHWTR.js";
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 as writeFileSync2 } from "fs";
17
- import { resolve as resolve3 } from "path";
21
+ import { writeFileSync } from "fs";
22
+ import { resolve as resolve2 } from "path";
18
23
  import inquirer from "inquirer";
19
- import chalk2 from "chalk";
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 resolve2, dirname } from "path";
70
- import chalk from "chalk";
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
- const refs = this.compileReferences(
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: "CLAUDE.md",
148
- content: claudeMd,
149
- overwriteStrategy: "skip-if-exists"
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
- if (agent.references?.length) {
195
- for (const ref of agent.references) {
196
- const refFrontmatter = this.formatFrontmatter({
197
- description: `${agent.name} reference: ${ref.title}`,
198
- alwaysApply: false,
199
- globs: globs || void 0
200
- });
201
- outputs.push({
202
- filePath: `.cursor/rules/${agent.id}-refs/${ref.id}.mdc`,
203
- content: `${refFrontmatter}
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
- overwriteStrategy: "replace"
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: ".cursor/rules/shared-conventions.mdc",
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
- const outputs = [];
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
- outputs.push({
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
- const refs = this.compileReferences(
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/references`
290
- );
291
- outputs.push(...refs);
657
+ `.codex/agents/${agent.id}-agent/skills`
658
+ ));
292
659
  }
293
660
  return outputs;
294
661
  }
295
- validate(outputs) {
296
- const errors = [];
297
- const warnings = [];
298
- const agentsMd = outputs.find((o) => o.filePath === "AGENTS.md");
299
- if (!agentsMd) {
300
- errors.push("AGENTS.md is missing from compiled output");
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 { valid: errors.length === 0, errors, warnings };
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
- // src/compilers/antigravity.compiler.ts
307
- var TOOL_MAP = {
308
- Read: "read_file",
309
- Write: "str_replace_editor",
310
- Edit: "str_replace_editor",
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
- const outputs = [];
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
- outputs.push({
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
- const refs = this.compileReferences(
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
- outputs.push(...refs);
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 = resolve2(cwd, output.filePath);
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
- writeFileSync(fullPath, existing + "\n" + output.content);
977
+ writeFileSync2(fullPath, existing + "\n" + output.content);
401
978
  return true;
402
979
  }
403
980
  return false;
404
981
  }
405
- mkdirSync(dir, { recursive: true });
406
- writeFileSync(fullPath, output.content);
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 agents = loadAgents(config, cwd);
412
- const platforms = options.platform ? [options.platform] : config.platforms;
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.compile(agents, config);
1077
+ const outputs = compiler.compileWithScope(agents, effectiveConfig, scopes);
418
1078
  const validation = compiler.validate(outputs);
419
1079
  if (!validation.valid) {
420
- console.log(chalk.red(`
1080
+ console.log(chalk2.red(`
421
1081
  \u2717 ${compiler.platform} validation errors:`));
422
1082
  for (const error of validation.errors) {
423
- console.log(chalk.red(` - ${error}`));
1083
+ console.log(chalk2.red(` - ${error}`));
424
1084
  }
425
1085
  continue;
426
1086
  }
427
1087
  for (const warning of validation.warnings) {
428
- console.log(chalk.yellow(` \u26A0 ${warning}`));
1088
+ console.log(chalk2.yellow(` \u26A0 ${warning}`));
429
1089
  totalWarnings++;
430
1090
  }
431
- let written = 0;
432
- for (const output of outputs) {
433
- if (writeOutput(output, cwd)) {
434
- written++;
435
- console.log(chalk.dim(` ${output.filePath}`));
436
- }
437
- }
438
- console.log(chalk.green(`\u2713 ${compiler.platform}: ${written} file(s) generated`));
439
- totalFiles += written;
1091
+ totalFiles += writeOutputs(outputs, cwd, compiler.platform);
440
1092
  }
441
- console.log(chalk.bold(`
1093
+ console.log(chalk2.bold(`
442
1094
  Total: ${totalFiles} file(s) generated`));
443
1095
  if (totalWarnings > 0) {
444
- console.log(chalk.yellow(`${totalWarnings} warning(s)`));
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.1.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();