agents-united 1.4.0 → 1.5.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.
Files changed (160) hide show
  1. package/README.md +54 -9
  2. package/dist/cli.js +706 -189
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +2 -1
  5. package/registry/agents/orchestrator-business.md +26 -2
  6. package/registry/agents/orchestrator-design.md +25 -2
  7. package/registry/agents/orchestrator-engineering.md +25 -2
  8. package/registry/agents/orchestrator-marketing.md +86 -5
  9. package/registry/agents/orchestrator-research.md +26 -2
  10. package/registry/agents/orchestrator-security.md +25 -2
  11. package/registry/agents/orchestrator-system-architecture.md +25 -2
  12. package/registry/agents/orchestrator-universal.md +26 -2
  13. package/registry/agents/subagent-accessibility-lead.md +11 -4
  14. package/registry/agents/subagent-ai-model-architect.md +26 -5
  15. package/registry/agents/subagent-android-architect.md +11 -4
  16. package/registry/agents/subagent-appsec-penetration-tester.md +189 -0
  17. package/registry/agents/subagent-backend-architect.md +15 -7
  18. package/registry/agents/subagent-business-panel-experts.md +13 -9
  19. package/registry/agents/subagent-cloud-infrastructure-architect.md +126 -0
  20. package/registry/agents/subagent-cloud-security-architect.md +221 -0
  21. package/registry/agents/subagent-code-reviewer.md +12 -9
  22. package/registry/agents/subagent-compliance-grc-specialist.md +147 -0
  23. package/registry/agents/subagent-cross-platform-specialist.md +11 -4
  24. package/registry/agents/subagent-data-engineer.md +10 -4
  25. package/registry/agents/subagent-database-administrator.md +141 -0
  26. package/registry/agents/subagent-deep-research.md +26 -6
  27. package/registry/agents/subagent-design-ops-lead.md +12 -8
  28. package/registry/agents/subagent-design-researcher.md +12 -8
  29. package/registry/agents/subagent-design-systems-architect.md +14 -9
  30. package/registry/agents/subagent-designer-toolkit-expert.md +30 -10
  31. package/registry/agents/subagent-devops-engineer.md +31 -11
  32. package/registry/agents/subagent-distributed-systems-architect.md +11 -4
  33. package/registry/agents/subagent-e2e-tester.md +24 -4
  34. package/registry/agents/subagent-financial-analyst.md +119 -0
  35. package/registry/agents/subagent-finops-cost-engineer.md +98 -0
  36. package/registry/agents/subagent-frontend-architect.md +30 -10
  37. package/registry/agents/subagent-interaction-designer.md +12 -6
  38. package/registry/agents/subagent-ios-architect.md +9 -3
  39. package/registry/agents/subagent-legal-contract-analyst.md +108 -0
  40. package/registry/agents/subagent-lifecycle-email-specialist.md +9 -3
  41. package/registry/agents/subagent-literature-patent-analyst.md +78 -0
  42. package/registry/agents/subagent-market-intelligence-analyst.md +110 -0
  43. package/registry/agents/subagent-marketing-campaign-specialist.md +11 -5
  44. package/registry/agents/subagent-marketing-content-strategist.md +13 -8
  45. package/registry/agents/subagent-marketing-conversion-specialist.md +11 -6
  46. package/registry/agents/subagent-marketing-creative-designer.md +14 -6
  47. package/registry/agents/subagent-marketing-growth-strategist.md +10 -6
  48. package/registry/agents/subagent-ml-platform-engineer.md +27 -6
  49. package/registry/agents/subagent-operations-strategist.md +85 -0
  50. package/registry/agents/subagent-paid-acquisition-specialist.md +10 -3
  51. package/registry/agents/subagent-plg-strategist.md +10 -4
  52. package/registry/agents/subagent-prototype-tester.md +25 -7
  53. package/registry/agents/subagent-qa-automation-lead.md +27 -4
  54. package/registry/agents/subagent-repo-index.md +10 -8
  55. package/registry/agents/subagent-security-engineer.md +12 -4
  56. package/registry/agents/subagent-seo-specialist.md +10 -4
  57. package/registry/agents/subagent-socratic-mentor.md +11 -4
  58. package/registry/agents/subagent-statistical-analyst.md +132 -0
  59. package/registry/agents/subagent-sysops-sre-lead.md +26 -4
  60. package/registry/agents/subagent-system-architect.md +13 -7
  61. package/registry/agents/subagent-ui-designer.md +9 -4
  62. package/registry/agents/subagent-ux-strategist.md +11 -6
  63. package/registry/bundles.json +436 -65
  64. package/registry/skills/ab-test-setup/SKILL.md +6 -3
  65. package/registry/skills/accessibility-audit/SKILL.md +6 -3
  66. package/registry/skills/ad-attribution-modeling/SKILL.md +7 -3
  67. package/registry/skills/ad-creative-design/SKILL.md +7 -4
  68. package/registry/skills/ai-prototype-refactoring/SKILL.md +8 -4
  69. package/registry/skills/architecture-design/SKILL.md +5 -3
  70. package/registry/skills/azure-infrastructure-bicep/SKILL.md +8 -4
  71. package/registry/skills/backend-api-design/SKILL.md +6 -3
  72. package/registry/skills/chaos-engineering/SKILL.md +7 -4
  73. package/registry/skills/churn-prevention-playbook/SKILL.md +7 -3
  74. package/registry/skills/ci-cd-pipeline-automation/SKILL.md +7 -4
  75. package/registry/skills/clickable-prototype-spec/SKILL.md +6 -3
  76. package/registry/skills/code-refactoring/SKILL.md +6 -3
  77. package/registry/skills/component-library-management/SKILL.md +6 -3
  78. package/registry/skills/component-playground-setup/SKILL.md +6 -3
  79. package/registry/skills/content-calendar-strategy/SKILL.md +6 -3
  80. package/registry/skills/conversion-funnel-optimization/SKILL.md +6 -3
  81. package/registry/skills/copywriting-frameworks/SKILL.md +6 -3
  82. package/registry/skills/database-design/SKILL.md +6 -3
  83. package/registry/skills/dependency-management/SKILL.md +6 -3
  84. package/registry/skills/design-handoff-spec/SKILL.md +6 -3
  85. package/registry/skills/design-ops-workflow/SKILL.md +6 -3
  86. package/registry/skills/design-system-governance/SKILL.md +6 -3
  87. package/registry/skills/design-system-tokens/SKILL.md +6 -3
  88. package/registry/skills/design-tokens-management/SKILL.md +6 -3
  89. package/registry/skills/design-version-control/SKILL.md +6 -3
  90. package/registry/skills/diagnosing-bugs/SKILL.md +6 -4
  91. package/registry/skills/docker-deployment/SKILL.md +6 -3
  92. package/registry/skills/domain-modeling/SKILL.md +6 -4
  93. package/registry/skills/email-drip-sequences/SKILL.md +7 -3
  94. package/registry/skills/email-marketing-automation/SKILL.md +6 -3
  95. package/registry/skills/finishing-a-development-branch/SKILL.md +6 -3
  96. package/registry/skills/frontend-component-design/SKILL.md +6 -3
  97. package/registry/skills/git-guardrails/SKILL.md +7 -4
  98. package/registry/skills/google-ads-optimization/SKILL.md +7 -4
  99. package/registry/skills/graphql-schema-design/SKILL.md +6 -3
  100. package/registry/skills/grill-me/SKILL.md +14 -8
  101. package/registry/skills/grill-with-docs/SKILL.md +15 -9
  102. package/registry/skills/growth-experiment-design/SKILL.md +6 -3
  103. package/registry/skills/handoff/SKILL.md +7 -4
  104. package/registry/skills/hf-model-evaluation/SKILL.md +8 -4
  105. package/registry/skills/interaction-pattern-library/SKILL.md +6 -3
  106. package/registry/skills/interactive-prototype-builder/SKILL.md +50 -40
  107. package/registry/skills/local-llm-inference/SKILL.md +7 -4
  108. package/registry/skills/maestro-mobile-testing/SKILL.md +7 -4
  109. package/registry/skills/marketing-creative-design/SKILL.md +7 -3
  110. package/registry/skills/mcp-setup/SKILL.md +370 -0
  111. package/registry/skills/meta-ad-creative-testing/SKILL.md +7 -4
  112. package/registry/skills/micro-interaction-design/SKILL.md +6 -3
  113. package/registry/skills/microservices-architecture/SKILL.md +6 -3
  114. package/registry/skills/mobile-android-design/SKILL.md +7 -4
  115. package/registry/skills/mobile-first-design/SKILL.md +6 -3
  116. package/registry/skills/mobile-ios-design/SKILL.md +7 -4
  117. package/registry/skills/mobile-platform-offline-validate/SKILL.md +8 -4
  118. package/registry/skills/modal-serverless-python/SKILL.md +7 -4
  119. package/registry/skills/onboarding-cro/SKILL.md +7 -3
  120. package/registry/skills/paid-acquisition-ppc/SKILL.md +7 -3
  121. package/registry/skills/performance-optimization/SKILL.md +6 -3
  122. package/registry/skills/playwright-best-practices/SKILL.md +7 -4
  123. package/registry/skills/product-launch-playbook/SKILL.md +6 -3
  124. package/registry/skills/programmatic-seo/SKILL.md +7 -3
  125. package/registry/skills/rag-vector-pipeline/SKILL.md +8 -4
  126. package/registry/skills/react-best-practices/SKILL.md +7 -4
  127. package/registry/skills/receiving-code-review/SKILL.md +6 -3
  128. package/registry/skills/replicate-model-inference/SKILL.md +7 -4
  129. package/registry/skills/requesting-code-review/SKILL.md +6 -3
  130. package/registry/skills/responsive-design-audit/SKILL.md +6 -3
  131. package/registry/skills/runpod-gpu-orchestration/SKILL.md +8 -4
  132. package/registry/skills/schema-markup-strategy/SKILL.md +7 -3
  133. package/registry/skills/security-audit/SKILL.md +6 -3
  134. package/registry/skills/seo-audit/SKILL.md +6 -3
  135. package/registry/skills/signup-flow-cro/SKILL.md +6 -3
  136. package/registry/skills/social-media-campaign/SKILL.md +6 -3
  137. package/registry/skills/state-driven-ui-animation/SKILL.md +6 -3
  138. package/registry/skills/subagent-driven-development/SKILL.md +6 -3
  139. package/registry/skills/supabase-backend-architecture/SKILL.md +7 -4
  140. package/registry/skills/systematic-debugging/SKILL.md +6 -3
  141. package/registry/skills/technical-documentation/SKILL.md +6 -3
  142. package/registry/skills/technical-seo-audit/SKILL.md +7 -4
  143. package/registry/skills/telemetry-monitoring/SKILL.md +7 -4
  144. package/registry/skills/test-driven-development/SKILL.md +5 -3
  145. package/registry/skills/to-spec/SKILL.md +14 -9
  146. package/registry/skills/to-tickets/SKILL.md +6 -4
  147. package/registry/skills/turso-distributed-sqlite/SKILL.md +8 -4
  148. package/registry/skills/ui-component-spec/SKILL.md +6 -3
  149. package/registry/skills/usability-testing-protocol/SKILL.md +6 -3
  150. package/registry/skills/user-flow-mapping/SKILL.md +6 -3
  151. package/registry/skills/user-journey-mapping/SKILL.md +6 -3
  152. package/registry/skills/vector-database-design/SKILL.md +8 -4
  153. package/registry/skills/vercel-deploy-best-practices/SKILL.md +8 -4
  154. package/registry/skills/viral-referral-loops/SKILL.md +7 -3
  155. package/registry/workflows/workflow-agency-ad-creative-sprint.md +50 -0
  156. package/registry/workflows/workflow-agency-brand-design-system.md +50 -0
  157. package/registry/workflows/workflow-agency-client-pitch-proposal.md +50 -0
  158. package/registry/workflows/workflow-agency-cro-funnel-teardown.md +50 -0
  159. package/registry/workflows/workflow-agency-full-campaign.md +58 -0
  160. package/registry/workflows/workflow-agency-seo-content-engine.md +50 -0
package/dist/cli.js CHANGED
@@ -4,8 +4,8 @@
4
4
  import { cac } from "cac";
5
5
  import pc from "picocolors";
6
6
  import { intro, outro, spinner, note, select, multiselect, confirm, text } from "@clack/prompts";
7
- import fs11 from "fs-extra";
8
- import path13 from "path";
7
+ import fs12 from "fs-extra";
8
+ import path14 from "path";
9
9
 
10
10
  // src/core/registry.ts
11
11
  import path from "path";
@@ -453,13 +453,13 @@ ${bodyStr}
453
453
  return yaml.stringify(manifest);
454
454
  }
455
455
  /**
456
- * Render the coordinator rule file (.cline/rules/agents-united-<bundle>.md).
456
+ * Render the coordinator rule file (.agents/plugins/<bundle>/rules/agents-united-<bundle>.md).
457
457
  * @param excludeAddons optional addon names to omit from the "Recommended Addon
458
458
  * Policy" list (used to stop advertising bundles already installed).
459
459
  */
460
460
  static renderCoordinatorRule(bundle, scope, excludeAddons = []) {
461
461
  const marker = `<!-- managed-by: agents-united | profile: cline | bundle: ${bundle.name} | do not edit -->`;
462
- const manifestRelPath = scope === "global" ? `~/.cline/agents-united/teams/${bundle.name}.yaml` : `.cline/agents-united/teams/${bundle.name}.yaml`;
462
+ const manifestRelPath = scope === "global" ? `~/.agents/plugins/${bundle.name}/agents-united/teams/${bundle.name}.yaml` : `.agents/plugins/${bundle.name}/agents-united/teams/${bundle.name}.yaml`;
463
463
  const coordinatorFile = bundle.orchestrator || `${bundle.name}.md`;
464
464
  const coordinatorName = coordinatorFile.replace(/\.md$/, "");
465
465
  const coordinatorCanonical = `agents/${coordinatorFile}`;
@@ -496,7 +496,26 @@ ${addonSection}
496
496
  */
497
497
  static async planCompoundProjection(bundle, scope, resolved, registryDir, excludeAddons = []) {
498
498
  const artifacts = [];
499
- const baseDir = scope === "global" ? ".cline" : ".cline";
499
+ const baseDir = `.agents/plugins/${bundle.name}`;
500
+ const pluginManifest = {
501
+ name: `agents-united-${bundle.name}`,
502
+ version: "1.0.0",
503
+ description: bundle.description || "",
504
+ cline: {
505
+ plugins: [
506
+ {
507
+ capabilities: ["skills", "tools", "workflows"],
508
+ skills: ["./skills"]
509
+ }
510
+ ]
511
+ }
512
+ };
513
+ artifacts.push({
514
+ kind: "plugin-manifest",
515
+ relPath: `${baseDir}/package.json`.replace(/\\/g, "/"),
516
+ content: JSON.stringify(pluginManifest, null, 2),
517
+ managedMarker: false
518
+ });
500
519
  for (const agentFile of resolved.agents) {
501
520
  const canonicalRel = `agents/${agentFile}`;
502
521
  const srcPath = path4.join(registryDir, "agents", agentFile);
@@ -593,7 +612,10 @@ var ANTIGRAVITY_ONLY_KEYS = [
593
612
  "commandExecutionPolicy",
594
613
  "mainAgent",
595
614
  "subagent",
596
- "hooks"
615
+ "hooks",
616
+ "inheritCustomizations",
617
+ "rules",
618
+ "effort"
597
619
  ];
598
620
  var FRONTMATTER_REGEX = /^---\r?\n([\s\S]+?)\r?\n---/;
599
621
  var HostProjector = class _HostProjector {
@@ -873,6 +895,19 @@ var InstallEngine = class _InstallEngine {
873
895
  asset.projectedTo.push(normProj);
874
896
  }
875
897
  }
898
+ removeProjectedTo(lockfile, canonicalRelPath, projectedRelPath) {
899
+ const normProj = this.toPosix(projectedRelPath);
900
+ const posixKey = canonicalRelPath.replace(/\\/g, "/");
901
+ const sysKey = canonicalRelPath.replace(/\//g, path5.sep);
902
+ const targetKey = lockfile.files[posixKey] ? posixKey : lockfile.files[sysKey] ? sysKey : canonicalRelPath;
903
+ const asset = lockfile.files[targetKey];
904
+ if (asset && asset.projectedTo) {
905
+ asset.projectedTo = asset.projectedTo.filter((p) => p !== normProj);
906
+ if (asset.projectedTo.length === 0) {
907
+ delete asset.projectedTo;
908
+ }
909
+ }
910
+ }
876
911
  async removeEmptyProjectionDirs(workspaceRoot, projPath) {
877
912
  let dir = path5.dirname(path5.join(workspaceRoot, projPath));
878
913
  while (dir !== workspaceRoot && dir.startsWith(workspaceRoot)) {
@@ -960,6 +995,40 @@ var InstallEngine = class _InstallEngine {
960
995
  (bundleDef.skills || []).forEach((s) => declared.add(`skills/${s}/SKILL.md`));
961
996
  (bundleDef.workflows || []).forEach((w) => declared.add(`workflows/${w}`));
962
997
  const artifacts = await ClineProjector.planCompoundProjection(bundleDef, scope, resolved, registryDir);
998
+ const newPaths = new Set(artifacts.map((a) => a.relPath));
999
+ if (lockfile.projections) {
1000
+ for (const [projRelPath, proj] of Object.entries(lockfile.projections)) {
1001
+ if (proj.host === "cline" && !newPaths.has(projRelPath) && proj.owners.includes(bundleDef.name)) {
1002
+ proj.owners = proj.owners.filter((o) => o !== bundleDef.name);
1003
+ if (proj.owners.length === 0) {
1004
+ const absProjection = path5.join(root, projRelPath);
1005
+ if (await fs3.pathExists(absProjection)) {
1006
+ await fs3.remove(absProjection);
1007
+ await this.removeEmptyProjectionDirs(root, projRelPath);
1008
+ }
1009
+ delete lockfile.projections[projRelPath];
1010
+ }
1011
+ if (proj.canonical) {
1012
+ this.removeProjectedTo(lockfile, proj.canonical, projRelPath);
1013
+ }
1014
+ }
1015
+ }
1016
+ }
1017
+ if (lockfile.files) {
1018
+ for (const [canonKey, fileMeta] of Object.entries(lockfile.files)) {
1019
+ if (fileMeta.projectedTo) {
1020
+ const staleClinePaths = fileMeta.projectedTo.filter((p) => p.startsWith(".cline/"));
1021
+ for (const stalePath of staleClinePaths) {
1022
+ const absPath = path5.join(root, stalePath);
1023
+ if (await fs3.pathExists(absPath)) {
1024
+ await fs3.remove(absPath);
1025
+ await this.removeEmptyProjectionDirs(root, stalePath);
1026
+ }
1027
+ this.removeProjectedTo(lockfile, canonKey, stalePath);
1028
+ }
1029
+ }
1030
+ }
1031
+ }
963
1032
  for (const artifact of artifacts) {
964
1033
  const dest = path5.join(root, artifact.relPath);
965
1034
  if (await fs3.pathExists(dest) && !options.force) {
@@ -989,7 +1058,7 @@ var InstallEngine = class _InstallEngine {
989
1058
  lockfile.projections = lockfile.projections || {};
990
1059
  const existingProj = lockfile.projections[artifact.relPath];
991
1060
  const bundleName = bundleDef.name;
992
- const declares = artifact.kind === "rule" || artifact.kind === "team-manifest" || (artifact.canonical ? declared.has(artifact.canonical) : false);
1061
+ const declares = artifact.kind === "rule" || artifact.kind === "team-manifest" || artifact.kind === "plugin-manifest" || (artifact.canonical ? declared.has(artifact.canonical) : false);
993
1062
  const priorOwners = existingProj?.owners ?? [];
994
1063
  const owners = declares ? Array.from(/* @__PURE__ */ new Set([...priorOwners, bundleName])) : priorOwners;
995
1064
  lockfile.projections[artifact.relPath] = {
@@ -2256,7 +2325,7 @@ var ClineLauncher = class _ClineLauncher {
2256
2325
  throw new Error(`Bundle '${bundleName}' is not installed in ${scope} scope.`);
2257
2326
  }
2258
2327
  const hasClineFanout = (lockfile.fanout || []).includes("cline");
2259
- const manifestRel = `.cline/agents-united/teams/${bundleName}.yaml`;
2328
+ const manifestRel = `.agents/plugins/${bundleName}/agents-united/teams/${bundleName}.yaml`;
2260
2329
  const manifestPath = path11.join(workspace, manifestRel);
2261
2330
  if (!hasClineFanout || !await fs9.pathExists(manifestPath)) {
2262
2331
  throw new Error(
@@ -2300,16 +2369,18 @@ var ClineLauncher = class _ClineLauncher {
2300
2369
  teamName = customTeamName;
2301
2370
  }
2302
2371
  const strategy = report.namedTeams ? "named-team" : "adaptive-session";
2303
- const manifestRel = scope === "global" ? `~/.cline/agents-united/teams/${bundleName}.yaml` : `.cline/agents-united/teams/${bundleName}.yaml`;
2372
+ const manifestRel = scope === "global" ? `~/.agents/plugins/${bundleName}/agents-united/teams/${bundleName}.yaml` : `.agents/plugins/${bundleName}/agents-united/teams/${bundleName}.yaml`;
2304
2373
  const coordinatorFile = (orchestrator || "orchestrator-engineering.md").replace(/\.md$/, "");
2305
2374
  const coordinatorCanonical = `.agents/agents/${coordinatorFile}.md`;
2306
2375
  const addonPolicyText = allowAddons ? "Addon auto-installation is pre-authorized for this session." : `Before installing any recommended addon, explain the requirement to the user and request explicit confirmation to run: agents add <addon> -t cline ${scope === "global" ? "-g " : ""}-y.`;
2376
+ const pluginInstallText = `Before proceeding, ensure you have installed this bundle's plugin by running: cline plugin install .agents/plugins/${bundleName}`;
2307
2377
  const taskText = prompt && prompt.trim().length > 0 ? `User task: ${prompt.trim()}` : "Please introduce your coordinator role to the user and ask for their first task.";
2308
2378
  const bootstrapPrompt = [
2309
2379
  `You are coordinating the "${bundleName}" team in Agents United.`,
2310
2380
  `Read the Team Manifest at "${manifestRel}" and your coordinator role definition at "${coordinatorCanonical}" before acting.`,
2311
2381
  `Use specialist roles only when necessary.`,
2312
2382
  addonPolicyText,
2383
+ pluginInstallText,
2313
2384
  taskText
2314
2385
  ].join("\n\n");
2315
2386
  const argv = [...command.prefixArgs];
@@ -2356,151 +2427,416 @@ var ClineLauncher = class _ClineLauncher {
2356
2427
  };
2357
2428
 
2358
2429
  // src/core/prerequisites.ts
2430
+ import path13 from "path";
2431
+ import os5 from "os";
2432
+ import fs11 from "fs-extra";
2433
+
2434
+ // src/core/mcp-locations.ts
2359
2435
  import path12 from "path";
2360
2436
  import os4 from "os";
2361
2437
  import fs10 from "fs-extra";
2362
- var PrerequisiteChecker = class _PrerequisiteChecker {
2438
+ var McpLocationRegistry = class _McpLocationRegistry {
2363
2439
  /**
2364
- * Discovers whether an MCP server is configured across supported host runtimes
2365
- * (Antigravity/Gemini, Cursor, Cline, Claude Code, etc.)
2440
+ * Declarative catalog of known MCP configuration files across AI tools, CLIs, extensions, and workspaces.
2366
2441
  */
2367
- static async isMcpConfigured(mcpName, cwd = process.cwd()) {
2368
- const normName = mcpName.trim().toLowerCase();
2369
- const homeDir = os4.homedir();
2370
- const localCursor = [
2371
- path12.join(cwd, ".cursor", "mcp.json"),
2372
- path12.join(cwd, "cursor.mcp.json")
2373
- ];
2374
- for (const cand of localCursor) {
2375
- if (await fs10.pathExists(cand)) {
2376
- try {
2377
- const config = await fs10.readJson(cand);
2378
- const servers = config?.mcpServers || config?.servers || config;
2379
- if (servers && (servers[normName] || servers[mcpName])) {
2380
- return { configured: true, host: "cursor", location: cand };
2381
- }
2382
- } catch {
2383
- }
2384
- }
2385
- }
2386
- const localCline = [
2387
- path12.join(cwd, "cline_mcp_settings.json"),
2388
- path12.join(cwd, ".cline", "mcp.json")
2389
- ];
2390
- for (const cand of localCline) {
2391
- if (await fs10.pathExists(cand)) {
2392
- try {
2393
- const config = await fs10.readJson(cand);
2394
- const servers = config?.mcpServers || config?.servers || config;
2395
- if (servers && (servers[normName] || servers[mcpName])) {
2396
- return { configured: true, host: "cline", location: cand };
2397
- }
2398
- } catch {
2399
- }
2400
- }
2442
+ static LOCATIONS = [
2443
+ // --- Google Antigravity & Gemini ---
2444
+ {
2445
+ id: "antigravity-global",
2446
+ host: "gemini",
2447
+ category: "cli",
2448
+ label: "Google Antigravity & Gemini Global Config",
2449
+ resolvePath: (_, home) => path12.join(home, ".gemini", "config", "mcp_config.json"),
2450
+ isPrimary: true
2451
+ },
2452
+ {
2453
+ id: "antigravity-system",
2454
+ host: "gemini",
2455
+ category: "desktop",
2456
+ label: "Google Antigravity System Config",
2457
+ resolvePath: (_, home) => path12.join(home, ".gemini", "antigravity", "mcp_config.json")
2458
+ },
2459
+ {
2460
+ id: "antigravity-workspace",
2461
+ host: "gemini",
2462
+ category: "workspace",
2463
+ label: "Google Antigravity Local Workspace Config",
2464
+ resolvePath: (cwd) => path12.join(cwd, ".gemini", "config", "mcp_config.json")
2465
+ },
2466
+ {
2467
+ id: "gemini-appdata",
2468
+ host: "gemini",
2469
+ category: "cli",
2470
+ label: "Google Gemini AppData Config",
2471
+ resolvePath: (_, __, appData) => path12.join(appData, "gemini", "config", "mcp_config.json")
2472
+ },
2473
+ // --- Cline CLI & VS Code Extension ---
2474
+ {
2475
+ id: "cline-cli-settings",
2476
+ host: "cline",
2477
+ category: "cli",
2478
+ label: "Cline CLI MCP Settings",
2479
+ resolvePath: (_, home) => path12.join(home, ".cline", "data", "settings", "cline_mcp_settings.json"),
2480
+ isPrimary: true
2481
+ },
2482
+ {
2483
+ id: "cline-extension-settings",
2484
+ host: "cline",
2485
+ category: "extension",
2486
+ label: "Cline VS Code Extension Global Settings",
2487
+ resolvePath: (_, __, appData) => path12.join(appData, "Code", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
2488
+ },
2489
+ {
2490
+ id: "cline-insiders-extension-settings",
2491
+ host: "cline",
2492
+ category: "extension",
2493
+ label: "Cline VS Code Insiders Extension Settings",
2494
+ resolvePath: (_, __, appData) => path12.join(appData, "Code - Insiders", "User", "globalStorage", "saoudrizwan.claude-dev", "settings", "cline_mcp_settings.json")
2495
+ },
2496
+ {
2497
+ id: "cline-legacy-settings",
2498
+ host: "cline",
2499
+ category: "cli",
2500
+ label: "Cline Home Legacy Settings",
2501
+ resolvePath: (_, home) => path12.join(home, ".cline", "settings", "cline_mcp_settings.json")
2502
+ },
2503
+ {
2504
+ id: "cline-home-flat",
2505
+ host: "cline",
2506
+ category: "cli",
2507
+ label: "Cline Home Flat Settings",
2508
+ resolvePath: (_, home) => path12.join(home, "cline_mcp_settings.json")
2509
+ },
2510
+ {
2511
+ id: "cline-workspace-flat",
2512
+ host: "cline",
2513
+ category: "workspace",
2514
+ label: "Cline Workspace Settings",
2515
+ resolvePath: (cwd) => path12.join(cwd, "cline_mcp_settings.json")
2516
+ },
2517
+ {
2518
+ id: "cline-workspace-dot",
2519
+ host: "cline",
2520
+ category: "workspace",
2521
+ label: "Cline Workspace .cline/mcp.json",
2522
+ resolvePath: (cwd) => path12.join(cwd, ".cline", "mcp.json")
2523
+ },
2524
+ // --- Roo Code Extension ---
2525
+ {
2526
+ id: "roo-code-extension-settings",
2527
+ host: "cline",
2528
+ category: "extension",
2529
+ label: "Roo Code VS Code Extension Settings",
2530
+ resolvePath: (_, __, appData) => path12.join(appData, "Code", "User", "globalStorage", "rooveterinaryinc.roo-cline", "settings", "cline_mcp_settings.json")
2531
+ },
2532
+ // --- Cursor IDE / CLI ---
2533
+ {
2534
+ id: "cursor-workspace",
2535
+ host: "cursor",
2536
+ category: "workspace",
2537
+ label: "Cursor Workspace Config",
2538
+ resolvePath: (cwd) => path12.join(cwd, ".cursor", "mcp.json"),
2539
+ isPrimary: true
2540
+ },
2541
+ {
2542
+ id: "cursor-global",
2543
+ host: "cursor",
2544
+ category: "desktop",
2545
+ label: "Cursor Global User Config",
2546
+ resolvePath: (_, home) => path12.join(home, ".cursor", "mcp.json")
2547
+ },
2548
+ // --- Claude Code CLI & Claude Desktop ---
2549
+ {
2550
+ id: "claude-workspace-dot",
2551
+ host: "claude",
2552
+ category: "workspace",
2553
+ label: "Claude Code Workspace Config",
2554
+ resolvePath: (cwd) => path12.join(cwd, ".claude", "mcp.json"),
2555
+ isPrimary: true
2556
+ },
2557
+ {
2558
+ id: "claude-workspace-flat",
2559
+ host: "claude",
2560
+ category: "workspace",
2561
+ label: "Claude Workspace claude.json",
2562
+ resolvePath: (cwd) => path12.join(cwd, "claude.json")
2563
+ },
2564
+ {
2565
+ id: "claude-global-dot",
2566
+ host: "claude",
2567
+ category: "cli",
2568
+ label: "Claude Code Global Config",
2569
+ resolvePath: (_, home) => path12.join(home, ".claude", "mcp.json")
2570
+ },
2571
+ {
2572
+ id: "claude-global-flat",
2573
+ host: "claude",
2574
+ category: "cli",
2575
+ label: "Claude Code Global claude.json",
2576
+ resolvePath: (_, home) => path12.join(home, "claude.json")
2577
+ },
2578
+ {
2579
+ id: "claude-desktop-global",
2580
+ host: "claude",
2581
+ category: "desktop",
2582
+ label: "Claude Desktop Global Config",
2583
+ resolvePath: (_, __, appData) => path12.join(appData, "Claude", "claude_desktop_config.json")
2584
+ },
2585
+ // --- Windsurf IDE ---
2586
+ {
2587
+ id: "windsurf-global",
2588
+ host: "windsurf",
2589
+ category: "desktop",
2590
+ label: "Windsurf Global Config",
2591
+ resolvePath: (_, home) => path12.join(home, ".codeium", "windsurf", "mcp_config.json"),
2592
+ isPrimary: true
2593
+ },
2594
+ {
2595
+ id: "windsurf-appdata",
2596
+ host: "windsurf",
2597
+ category: "desktop",
2598
+ label: "Windsurf AppData Config",
2599
+ resolvePath: (_, __, appData) => path12.join(appData, "Windsurf", "mcp_config.json")
2600
+ },
2601
+ // --- OpenCode & Codex ---
2602
+ {
2603
+ id: "opencode-workspace",
2604
+ host: "opencode",
2605
+ category: "workspace",
2606
+ label: "OpenCode Workspace Config",
2607
+ resolvePath: (cwd) => path12.join(cwd, ".opencode", "mcp.json"),
2608
+ isPrimary: true
2609
+ },
2610
+ {
2611
+ id: "opencode-global",
2612
+ host: "opencode",
2613
+ category: "cli",
2614
+ label: "OpenCode Global Config",
2615
+ resolvePath: (_, home) => path12.join(home, ".config", "opencode", "mcp.json")
2401
2616
  }
2402
- const localClaude = [
2403
- path12.join(cwd, "claude.json"),
2404
- path12.join(cwd, ".claude", "mcp.json")
2405
- ];
2406
- for (const cand of localClaude) {
2407
- if (await fs10.pathExists(cand)) {
2617
+ ];
2618
+ /**
2619
+ * Discovers all MCP configuration files across the filesystem, inspecting existence and parsing server definitions.
2620
+ */
2621
+ static async discoverAll(cwd = process.cwd()) {
2622
+ const homeDir = os4.homedir();
2623
+ const appData = process.env.APPDATA || (process.platform === "darwin" ? path12.join(homeDir, "Library", "Application Support") : path12.join(homeDir, ".config"));
2624
+ const results = [];
2625
+ const seenPaths = /* @__PURE__ */ new Set();
2626
+ for (const desc of _McpLocationRegistry.LOCATIONS) {
2627
+ const resolved = path12.normalize(desc.resolvePath(cwd, homeDir, appData));
2628
+ const key = resolved.toLowerCase();
2629
+ if (seenPaths.has(key)) continue;
2630
+ seenPaths.add(key);
2631
+ const exists = await fs10.pathExists(resolved);
2632
+ let serverCount = 0;
2633
+ let servers;
2634
+ if (exists) {
2408
2635
  try {
2409
- const config = await fs10.readJson(cand);
2410
- const servers = config?.mcpServers || config?.servers || config;
2411
- if (servers && (servers[normName] || servers[mcpName])) {
2412
- return { configured: true, host: "claude", location: cand };
2636
+ const config = await fs10.readJson(resolved);
2637
+ const rawServers = config?.mcpServers || config?.servers || config;
2638
+ if (rawServers && typeof rawServers === "object") {
2639
+ servers = rawServers;
2640
+ serverCount = Object.keys(rawServers).length;
2413
2641
  }
2414
2642
  } catch {
2415
2643
  }
2416
2644
  }
2645
+ results.push({
2646
+ id: desc.id,
2647
+ host: desc.host,
2648
+ category: desc.category,
2649
+ label: desc.label,
2650
+ path: resolved,
2651
+ exists,
2652
+ serverCount,
2653
+ servers,
2654
+ isPrimary: desc.isPrimary
2655
+ });
2417
2656
  }
2418
- const localGemini = [
2419
- path12.join(cwd, ".gemini", "antigravity", "mcp", normName),
2420
- path12.join(cwd, ".gemini", "antigravity", "mcp")
2421
- ];
2422
- for (const cand of localGemini) {
2423
- if (await fs10.pathExists(cand)) {
2424
- if (cand.endsWith(normName)) {
2425
- return { configured: true, host: "gemini", location: cand };
2426
- }
2427
- const entries = await fs10.readdir(cand).catch(() => []);
2428
- if (entries.some((e) => e.toLowerCase() === normName || e.toLowerCase().startsWith(`${normName}.`))) {
2429
- return { configured: true, host: "gemini", location: cand };
2430
- }
2431
- }
2657
+ return results;
2658
+ }
2659
+ /**
2660
+ * Returns discovered locations filtered for specific host(s).
2661
+ */
2662
+ static async discoverForHosts(hosts, cwd = process.cwd()) {
2663
+ const all = await _McpLocationRegistry.discoverAll(cwd);
2664
+ const hostSet = new Set(hosts.map((h) => h === "agents" ? "gemini" : h));
2665
+ return all.filter((loc) => hostSet.has(loc.host));
2666
+ }
2667
+ /**
2668
+ * Resolves the primary target write path for a given host runtime.
2669
+ */
2670
+ static getPrimaryWritePath(host, cwd = process.cwd()) {
2671
+ const homeDir = os4.homedir();
2672
+ const appData = process.env.APPDATA || (process.platform === "darwin" ? path12.join(homeDir, "Library", "Application Support") : path12.join(homeDir, ".config"));
2673
+ const targetHost = host === "agents" ? "gemini" : host;
2674
+ const desc = _McpLocationRegistry.LOCATIONS.find((l) => l.host === targetHost && l.isPrimary);
2675
+ if (desc) {
2676
+ return path12.normalize(desc.resolvePath(cwd, homeDir, appData));
2432
2677
  }
2433
- const globalGemini = [
2434
- path12.join(homeDir, ".gemini", "antigravity", "mcp", normName),
2435
- path12.join(homeDir, ".gemini", "antigravity", "mcp")
2436
- ];
2437
- for (const cand of globalGemini) {
2438
- if (await fs10.pathExists(cand)) {
2439
- if (cand.endsWith(normName)) {
2440
- return { configured: true, host: "gemini", location: cand };
2441
- }
2442
- const entries = await fs10.readdir(cand).catch(() => []);
2443
- if (entries.some((e) => e.toLowerCase() === normName || e.toLowerCase().startsWith(`${normName}.`))) {
2444
- return { configured: true, host: "gemini", location: cand };
2445
- }
2678
+ return path12.normalize(path12.join(cwd, ".cursor", "mcp.json"));
2679
+ }
2680
+ };
2681
+
2682
+ // src/core/prerequisites.ts
2683
+ var PrerequisiteChecker = class _PrerequisiteChecker {
2684
+ /**
2685
+ * Discovers all candidate and existing MCP configuration files across AI hosts
2686
+ */
2687
+ static async discoverHostConfigFiles(cwd = process.cwd()) {
2688
+ const discovered = await McpLocationRegistry.discoverAll(cwd);
2689
+ return discovered.map((d) => ({
2690
+ host: d.host,
2691
+ label: d.label,
2692
+ path: d.path,
2693
+ exists: d.exists,
2694
+ serverCount: d.serverCount
2695
+ }));
2696
+ }
2697
+ /**
2698
+ * Helper that checks if a configured MCP server key or its configuration payload matches the target MCP name
2699
+ */
2700
+ static matchesMcpServer(targetMcpName, serverKey, serverConfig = {}) {
2701
+ const targetNorm = targetMcpName.toLowerCase().replace(/[^a-z0-9]/g, "");
2702
+ const keyNorm = serverKey.toLowerCase().replace(/[^a-z0-9]/g, "");
2703
+ if (keyNorm === targetNorm) return true;
2704
+ if (keyNorm.includes(targetNorm)) return true;
2705
+ if (targetNorm.includes(keyNorm)) return true;
2706
+ const strippedKey = keyNorm.replace(/^githubcom/g, "").replace(/^mcp/g, "").replace(/mcp$/g, "").replace(/^server/g, "").replace(/server$/g, "");
2707
+ if (strippedKey === targetNorm || strippedKey.length > 2 && targetNorm.includes(strippedKey) || targetNorm.length > 2 && strippedKey.includes(targetNorm)) {
2708
+ return true;
2709
+ }
2710
+ const cmd = String(serverConfig?.command || "").toLowerCase();
2711
+ const args = Array.isArray(serverConfig?.args) ? serverConfig.args.map((a) => String(a).toLowerCase()).join(" ") : "";
2712
+ const fullExec = `${cmd} ${args}`;
2713
+ if (targetMcpName === "github") {
2714
+ if (fullExec.includes("github") || fullExec.includes("ghcr.io/github")) return true;
2715
+ }
2716
+ if (targetMcpName === "playwright") {
2717
+ if (fullExec.includes("playwright")) return true;
2718
+ }
2719
+ if (targetMcpName === "markitdown") {
2720
+ if (fullExec.includes("markitdown")) return true;
2721
+ }
2722
+ if (targetMcpName === "chrome-devtools-mcp" || targetMcpName === "chrome-devtools") {
2723
+ if (fullExec.includes("chrome-devtools")) return true;
2724
+ }
2725
+ if (targetMcpName === "stitch") {
2726
+ if (fullExec.includes("stitch") || fullExec.includes("stitch.googleapis.com")) return true;
2727
+ }
2728
+ if (targetMcpName === "figma") {
2729
+ if (fullExec.includes("figma")) return true;
2730
+ }
2731
+ if (targetMcpName === "firecrawl") {
2732
+ if (fullExec.includes("firecrawl")) return true;
2733
+ }
2734
+ if (targetMcpName === "context7") {
2735
+ if (fullExec.includes("context7")) return true;
2736
+ }
2737
+ if (targetMcpName === "supabase") {
2738
+ if (fullExec.includes("supabase")) return true;
2739
+ }
2740
+ const url = String(serverConfig?.url || serverConfig?.serverUrl || "").toLowerCase();
2741
+ if (url.includes(targetNorm)) return true;
2742
+ if (targetMcpName === "stitch" && url.includes("stitch.googleapis.com")) return true;
2743
+ if (targetMcpName === "context7" && url.includes("context7.com")) return true;
2744
+ if (targetMcpName === "firecrawl" && url.includes("firecrawl.dev")) return true;
2745
+ if (targetMcpName === "supabase" && url.includes("supabase.com")) return true;
2746
+ return false;
2747
+ }
2748
+ /**
2749
+ * Discovers whether an MCP server is configured across supported host runtimes
2750
+ * (Antigravity/Gemini, Cursor, Cline, Claude Code, etc.)
2751
+ */
2752
+ static async isMcpConfigured(mcpName, cwd = process.cwd()) {
2753
+ const discovered = await McpLocationRegistry.discoverAll(cwd);
2754
+ const foundInConfigs = [];
2755
+ const missingInConfigs = [];
2756
+ for (const file of discovered) {
2757
+ if (!file.exists) {
2758
+ missingInConfigs.push({
2759
+ id: file.id,
2760
+ host: file.host,
2761
+ label: file.label,
2762
+ path: file.path
2763
+ });
2764
+ continue;
2446
2765
  }
2447
- }
2448
- const globalCursor = [path12.join(homeDir, ".cursor", "mcp.json")];
2449
- for (const cand of globalCursor) {
2450
- if (await fs10.pathExists(cand)) {
2451
- try {
2452
- const config = await fs10.readJson(cand);
2453
- const servers = config?.mcpServers || config?.servers || config;
2454
- if (servers && (servers[normName] || servers[mcpName])) {
2455
- return { configured: true, host: "cursor", location: cand };
2766
+ let matched = false;
2767
+ if (file.servers && typeof file.servers === "object") {
2768
+ for (const [key, serverDef] of Object.entries(file.servers)) {
2769
+ if (_PrerequisiteChecker.matchesMcpServer(mcpName, key, serverDef)) {
2770
+ const isDisabled = serverDef?.disabled === true;
2771
+ foundInConfigs.push({
2772
+ id: file.id,
2773
+ host: file.host,
2774
+ label: file.label,
2775
+ path: file.path,
2776
+ disabled: isDisabled,
2777
+ serverKey: key
2778
+ });
2779
+ matched = true;
2780
+ break;
2456
2781
  }
2457
- } catch {
2458
2782
  }
2459
2783
  }
2460
- }
2461
- const globalCline = [path12.join(homeDir, "cline_mcp_settings.json")];
2462
- for (const cand of globalCline) {
2463
- if (await fs10.pathExists(cand)) {
2464
- try {
2465
- const config = await fs10.readJson(cand);
2466
- const servers = config?.mcpServers || config?.servers || config;
2467
- if (servers && (servers[normName] || servers[mcpName])) {
2468
- return { configured: true, host: "cline", location: cand };
2469
- }
2470
- } catch {
2471
- }
2784
+ if (!matched) {
2785
+ missingInConfigs.push({
2786
+ id: file.id,
2787
+ host: file.host,
2788
+ label: file.label,
2789
+ path: file.path
2790
+ });
2472
2791
  }
2473
2792
  }
2474
- const globalClaude = [
2475
- path12.join(homeDir, "claude.json"),
2476
- path12.join(homeDir, ".claude", "mcp.json")
2793
+ const homeDir = os5.homedir();
2794
+ const dirCandidates = [
2795
+ path13.join(cwd, ".gemini", "antigravity", "mcp"),
2796
+ path13.join(homeDir, ".gemini", "antigravity", "mcp")
2477
2797
  ];
2478
- for (const cand of globalClaude) {
2479
- if (await fs10.pathExists(cand)) {
2480
- try {
2481
- const config = await fs10.readJson(cand);
2482
- const servers = config?.mcpServers || config?.servers || config;
2483
- if (servers && (servers[normName] || servers[mcpName])) {
2484
- return { configured: true, host: "claude", location: cand };
2798
+ for (const dir of dirCandidates) {
2799
+ if (await fs11.pathExists(dir)) {
2800
+ const entries = await fs11.readdir(dir).catch(() => []);
2801
+ for (const entry of entries) {
2802
+ if (_PrerequisiteChecker.matchesMcpServer(mcpName, entry, {})) {
2803
+ foundInConfigs.push({
2804
+ id: "antigravity-dir",
2805
+ host: "gemini",
2806
+ label: "Google Antigravity MCP Directory",
2807
+ path: path13.join(dir, entry),
2808
+ disabled: false,
2809
+ serverKey: entry
2810
+ });
2811
+ break;
2485
2812
  }
2486
- } catch {
2487
2813
  }
2488
2814
  }
2489
2815
  }
2490
- return { configured: false };
2816
+ const isConfigured = foundInConfigs.length > 0;
2817
+ const firstFound = foundInConfigs[0];
2818
+ return {
2819
+ configured: isConfigured,
2820
+ host: firstFound?.host,
2821
+ location: firstFound?.path,
2822
+ disabled: firstFound?.disabled,
2823
+ serverKey: firstFound?.serverKey,
2824
+ foundInConfigs,
2825
+ missingInConfigs
2826
+ };
2491
2827
  }
2492
2828
  /**
2493
2829
  * Checks if an npm package is installed in node_modules or declared in package.json
2494
2830
  */
2495
2831
  static async isPackageInstalled(pkgName, cwd = process.cwd()) {
2496
- const modulePath = path12.join(cwd, "node_modules", ...pkgName.split("/"));
2497
- if (await fs10.pathExists(modulePath)) {
2832
+ const modulePath = path13.join(cwd, "node_modules", ...pkgName.split("/"));
2833
+ if (await fs11.pathExists(modulePath)) {
2498
2834
  return { installed: true, location: modulePath };
2499
2835
  }
2500
- const pkgJsonPath = path12.join(cwd, "package.json");
2501
- if (await fs10.pathExists(pkgJsonPath)) {
2836
+ const pkgJsonPath = path13.join(cwd, "package.json");
2837
+ if (await fs11.pathExists(pkgJsonPath)) {
2502
2838
  try {
2503
- const pkg = await fs10.readJson(pkgJsonPath);
2839
+ const pkg = await fs11.readJson(pkgJsonPath);
2504
2840
  const deps = {
2505
2841
  ...pkg.dependencies,
2506
2842
  ...pkg.devDependencies,
@@ -2523,20 +2859,20 @@ var PrerequisiteChecker = class _PrerequisiteChecker {
2523
2859
  return { set: true, source: "process.env" };
2524
2860
  }
2525
2861
  const envFiles = [
2526
- path12.join(cwd, ".env.local"),
2527
- path12.join(cwd, ".env")
2862
+ path13.join(cwd, ".env.local"),
2863
+ path13.join(cwd, ".env")
2528
2864
  ];
2529
2865
  for (const envFile of envFiles) {
2530
- if (await fs10.pathExists(envFile)) {
2866
+ if (await fs11.pathExists(envFile)) {
2531
2867
  try {
2532
- const content = await fs10.readFile(envFile, "utf8");
2868
+ const content = await fs11.readFile(envFile, "utf8");
2533
2869
  const lines = content.split("\n");
2534
2870
  for (const line of lines) {
2535
2871
  const trimmed = line.trim();
2536
2872
  if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
2537
2873
  const [k, ...v] = trimmed.split("=");
2538
2874
  if (k.trim() === varName && v.join("=").trim() !== "") {
2539
- return { set: true, source: path12.basename(envFile) };
2875
+ return { set: true, source: path13.basename(envFile) };
2540
2876
  }
2541
2877
  }
2542
2878
  } catch {
@@ -2546,25 +2882,60 @@ var PrerequisiteChecker = class _PrerequisiteChecker {
2546
2882
  return { set: false };
2547
2883
  }
2548
2884
  /**
2549
- * Evaluates all prerequisites declared on a bundle
2885
+ * Evaluates all prerequisites declared on a bundle, supporting target host scoping and multi-host partial breakdowns
2550
2886
  */
2551
2887
  async evaluate(bundle, options = {}) {
2552
2888
  const cwd = options.cwd || process.cwd();
2553
2889
  const env = options.env || process.env;
2554
2890
  const tier = bundle.tier || "domain";
2555
2891
  const prereqs = bundle.prerequisites || {};
2892
+ const targetHosts = options.targetHosts || ["agents"];
2893
+ const targetHostKeys = new Set(targetHosts.map((h) => h === "agents" ? "gemini" : h));
2556
2894
  const items = [];
2557
2895
  if (prereqs.requiredMcps && prereqs.requiredMcps.length > 0) {
2558
2896
  for (const mcp of prereqs.requiredMcps) {
2559
2897
  const check = await _PrerequisiteChecker.isMcpConfigured(mcp.name, cwd);
2898
+ const relevantFound = check.foundInConfigs.filter((c) => targetHostKeys.has(c.host));
2899
+ const hostCleanNames = {
2900
+ gemini: "Google Antigravity",
2901
+ agents: "Google Antigravity",
2902
+ cline: "Cline",
2903
+ cursor: "Cursor",
2904
+ claude: "Claude Code",
2905
+ opencode: "OpenCode",
2906
+ windsurf: "Windsurf"
2907
+ };
2908
+ const detectedHostLabels = Array.from(new Set(relevantFound.map((c) => hostCleanNames[c.host] || c.host)));
2909
+ const detectedHostKeys = new Set(relevantFound.map((c) => c.host));
2910
+ const missingHostKeys = Array.from(targetHostKeys).filter((h) => !detectedHostKeys.has(h));
2911
+ const missingHostLabels = missingHostKeys.map((h) => hostCleanNames[h] || h);
2912
+ let satisfied = false;
2913
+ let status = "missing";
2914
+ let details = "Not found in host MCP configuration";
2915
+ if (relevantFound.length > 0 && missingHostKeys.length === 0) {
2916
+ satisfied = true;
2917
+ status = "ok";
2918
+ details = `Configured in ${detectedHostLabels.join(", ")}`;
2919
+ } else if (relevantFound.length > 0 && missingHostKeys.length > 0) {
2920
+ satisfied = false;
2921
+ status = "partial";
2922
+ details = `Detected in ${detectedHostLabels.join(", ")}; Missing in ${missingHostLabels.join(", ")}`;
2923
+ } else if (check.foundInConfigs.length > 0 && relevantFound.length === 0) {
2924
+ const otherLabels = Array.from(new Set(check.foundInConfigs.map((c) => hostCleanNames[c.host] || c.host)));
2925
+ satisfied = false;
2926
+ status = "partial";
2927
+ details = `Detected in ${otherLabels.join(", ")}; Missing in target (${Array.from(targetHostKeys).map((h) => hostCleanNames[h] || h).join(", ")})`;
2928
+ }
2560
2929
  items.push({
2561
2930
  type: "mcp",
2562
2931
  name: mcp.name,
2563
2932
  purpose: mcp.purpose,
2564
- satisfied: check.configured,
2565
- status: check.configured ? "ok" : "missing",
2566
- details: check.configured ? `Configured in ${check.host || "host"}` : "Not found in host MCP configuration",
2567
- optionalForBrainstorming: mcp.optionalForBrainstorming ?? true
2933
+ satisfied,
2934
+ status,
2935
+ details,
2936
+ optionalForBrainstorming: mcp.optionalForBrainstorming ?? true,
2937
+ detectedInHosts: detectedHostLabels,
2938
+ missingInHosts: missingHostLabels
2568
2939
  });
2569
2940
  }
2570
2941
  }
@@ -2607,6 +2978,175 @@ var PrerequisiteChecker = class _PrerequisiteChecker {
2607
2978
  modes: bundle.modes
2608
2979
  };
2609
2980
  }
2981
+ /**
2982
+ * Returns canonical command and environment definitions for known MCP servers
2983
+ */
2984
+ static getMcpDefinition(mcpName, mode = "operational", envVars = {}) {
2985
+ const norm = mcpName.trim().toLowerCase();
2986
+ switch (norm) {
2987
+ case "github":
2988
+ return {
2989
+ command: "npx",
2990
+ args: ["-y", "@modelcontextprotocol/server-github"],
2991
+ ...mode === "operational" && (envVars.GITHUB_PERSONAL_ACCESS_TOKEN || process.env.GITHUB_PERSONAL_ACCESS_TOKEN) ? { env: { GITHUB_PERSONAL_ACCESS_TOKEN: envVars.GITHUB_PERSONAL_ACCESS_TOKEN || process.env.GITHUB_PERSONAL_ACCESS_TOKEN || "" } } : {}
2992
+ };
2993
+ case "firecrawl":
2994
+ return {
2995
+ command: "npx",
2996
+ args: ["-y", "firecrawl-mcp"],
2997
+ ...mode === "operational" && (envVars.FIRECRAWL_API_KEY || process.env.FIRECRAWL_API_KEY) ? { env: { FIRECRAWL_API_KEY: envVars.FIRECRAWL_API_KEY || process.env.FIRECRAWL_API_KEY || "" } } : mode === "limited-operational" && envVars.FIRECRAWL_API_URL ? { env: { FIRECRAWL_API_URL: envVars.FIRECRAWL_API_URL } } : {}
2998
+ };
2999
+ case "context7":
3000
+ return {
3001
+ command: "npx",
3002
+ args: ["-y", "@upstash/context7-mcp"],
3003
+ ...mode === "operational" && envVars.UPSTASH_REDIS_REST_URL && envVars.UPSTASH_REDIS_REST_TOKEN ? { env: { UPSTASH_REDIS_REST_URL: envVars.UPSTASH_REDIS_REST_URL, UPSTASH_REDIS_REST_TOKEN: envVars.UPSTASH_REDIS_REST_TOKEN } } : {}
3004
+ };
3005
+ case "playwright":
3006
+ return {
3007
+ command: "npx",
3008
+ args: ["-y", "@executeautomation/playwright-mcp-server"]
3009
+ };
3010
+ case "markitdown":
3011
+ return {
3012
+ command: "uvx",
3013
+ args: ["markitdown-mcp"]
3014
+ };
3015
+ case "chrome-devtools-mcp":
3016
+ case "chrome-devtools":
3017
+ return {
3018
+ command: "npx",
3019
+ args: ["-y", "chrome-devtools-mcp"]
3020
+ };
3021
+ case "stitch":
3022
+ return {
3023
+ command: "npx",
3024
+ args: ["-y", "mcp-remote", "https://stitch.googleapis.com/mcp"],
3025
+ ...mode === "operational" && (envVars.STITCH_API_KEY || process.env.STITCH_API_KEY) ? { env: { STITCH_API_KEY: envVars.STITCH_API_KEY || process.env.STITCH_API_KEY || "" } } : {}
3026
+ };
3027
+ case "figma":
3028
+ return {
3029
+ command: "npx",
3030
+ args: ["-y", "ai-figma-mcp"],
3031
+ ...mode === "operational" && (envVars.FIGMA_ACCESS_TOKEN || process.env.FIGMA_ACCESS_TOKEN) ? { env: { FIGMA_ACCESS_TOKEN: envVars.FIGMA_ACCESS_TOKEN || process.env.FIGMA_ACCESS_TOKEN || "" } } : {}
3032
+ };
3033
+ default:
3034
+ return {
3035
+ command: "npx",
3036
+ args: ["-y", norm]
3037
+ };
3038
+ }
3039
+ }
3040
+ /**
3041
+ * Generates client-specific MCP configuration objects for Cursor, Cline, Claude, or Antigravity
3042
+ */
3043
+ static generateClientConfig(client, mcpNames, mode = "operational", envVars = {}) {
3044
+ const servers = {};
3045
+ for (const name of mcpNames) {
3046
+ const def = _PrerequisiteChecker.getMcpDefinition(name, mode, envVars);
3047
+ if (client === "cline") {
3048
+ servers[name] = {
3049
+ ...def,
3050
+ disabled: false,
3051
+ autoApprove: []
3052
+ };
3053
+ } else {
3054
+ servers[name] = def;
3055
+ }
3056
+ }
3057
+ return { mcpServers: servers };
3058
+ }
3059
+ /**
3060
+ * Attempts to automatically provision a missing MCP server using the native CLI.
3061
+ */
3062
+ static async provisionMcpServer(mcpName, options = {}) {
3063
+ try {
3064
+ const { execSync } = await import("child_process");
3065
+ const cmd = `npx @antigravity/cli mcp add ${mcpName} --type stdio`;
3066
+ const output = execSync(cmd, {
3067
+ cwd: options.cwd || process.cwd(),
3068
+ env: options.env || process.env,
3069
+ encoding: "utf8"
3070
+ });
3071
+ return { success: true, output };
3072
+ } catch (err) {
3073
+ return { success: false, output: err.message || String(err) };
3074
+ }
3075
+ }
3076
+ /**
3077
+ * Automatically configures missing MCP servers into a specific MCP JSON configuration file,
3078
+ * activating disabled servers and appending missing definitions.
3079
+ */
3080
+ static async autoConfigureConfigFile(targetFilePath, mcpNames, mode = "operational", envVars = {}) {
3081
+ await fs11.ensureDir(path13.dirname(targetFilePath));
3082
+ let existingConfig = {};
3083
+ if (await fs11.pathExists(targetFilePath)) {
3084
+ try {
3085
+ existingConfig = await fs11.readJson(targetFilePath);
3086
+ } catch {
3087
+ existingConfig = {};
3088
+ }
3089
+ }
3090
+ const isServersProp = Boolean(existingConfig.servers && !existingConfig.mcpServers);
3091
+ const existingServers = (isServersProp ? existingConfig.servers : existingConfig.mcpServers) || {};
3092
+ const addedServers = [];
3093
+ const enabledServers = [];
3094
+ for (const mcp of mcpNames) {
3095
+ let foundKey = null;
3096
+ for (const [key, serverDef] of Object.entries(existingServers)) {
3097
+ if (_PrerequisiteChecker.matchesMcpServer(mcp, key, serverDef)) {
3098
+ foundKey = key;
3099
+ if (serverDef?.disabled === true) {
3100
+ existingServers[key].disabled = false;
3101
+ enabledServers.push(key);
3102
+ }
3103
+ break;
3104
+ }
3105
+ }
3106
+ if (!foundKey) {
3107
+ const def = _PrerequisiteChecker.getMcpDefinition(mcp, mode, envVars);
3108
+ existingServers[mcp] = def;
3109
+ addedServers.push(mcp);
3110
+ }
3111
+ }
3112
+ if (isServersProp) {
3113
+ existingConfig.servers = existingServers;
3114
+ } else {
3115
+ existingConfig.mcpServers = existingServers;
3116
+ }
3117
+ await fs11.writeJson(targetFilePath, existingConfig, { spaces: 2 });
3118
+ return {
3119
+ success: true,
3120
+ targetFile: targetFilePath,
3121
+ addedServers,
3122
+ enabledServers
3123
+ };
3124
+ }
3125
+ /**
3126
+ * Automatically configures missing MCP servers into a specific AI host's configuration file.
3127
+ */
3128
+ static async autoConfigureHost(host, mcpNames, cwd = process.cwd(), mode = "operational", envVars = {}) {
3129
+ const targetFile = McpLocationRegistry.getPrimaryWritePath(host, cwd);
3130
+ const res = await _PrerequisiteChecker.autoConfigureConfigFile(targetFile, mcpNames, mode, envVars);
3131
+ return {
3132
+ configured: res.success,
3133
+ targetFile: res.targetFile,
3134
+ addedServers: [...res.addedServers, ...res.enabledServers]
3135
+ };
3136
+ }
3137
+ /**
3138
+ * Automatically installs missing NPM packages into the workspace.
3139
+ */
3140
+ static async autoInstallPackages(packages, cwd = process.cwd()) {
3141
+ try {
3142
+ const { execSync } = await import("child_process");
3143
+ const cmd = `npm install -D ${packages.join(" ")}`;
3144
+ const output = execSync(cmd, { cwd, encoding: "utf8" });
3145
+ return { success: true, output };
3146
+ } catch (err) {
3147
+ return { success: false, output: err.message || String(err) };
3148
+ }
3149
+ }
2610
3150
  };
2611
3151
 
2612
3152
  // src/cli.ts
@@ -2619,7 +3159,7 @@ var updater = new UpdateEngine(registry, scanner, installer);
2619
3159
  function detectWorkspaceHosts(cwd = process.cwd()) {
2620
3160
  const detected = [];
2621
3161
  for (const host of Object.values(HOST_REGISTRY)) {
2622
- const found = host.detectionMarkers.some((marker) => fs11.pathExistsSync(path13.join(cwd, marker)));
3162
+ const found = host.detectionMarkers.some((marker) => fs12.pathExistsSync(path14.join(cwd, marker)));
2623
3163
  if (found) detected.push(host.id);
2624
3164
  }
2625
3165
  return detected;
@@ -3082,71 +3622,40 @@ To bypass this gate and install draft assets anyway, pass: --allow-under-constru
3082
3622
  let executionMode = options.mode || "operational";
3083
3623
  if (targetBundleDef && (targetBundleDef.prerequisites || targetBundleDef.tier === "organization")) {
3084
3624
  const checker = new PrerequisiteChecker();
3085
- const prereqEval = await checker.evaluate(targetBundleDef);
3625
+ const prereqEval = await checker.evaluate(targetBundleDef, { cwd: process.cwd(), targetHosts: hosts });
3086
3626
  if (prereqEval.hasPrerequisites) {
3087
3627
  const checkLines = [];
3088
3628
  for (const item of prereqEval.items) {
3089
3629
  const typeLabel = item.type === "mcp" ? "MCP" : item.type === "env" ? "Env" : "Pkg";
3090
- const icon = item.satisfied ? pc.green("\u2713") : pc.red("\u2717");
3630
+ let icon = pc.green("\u2713");
3631
+ let statusText = pc.green("Detected");
3632
+ if (!item.satisfied) {
3633
+ if (item.status === "partial") {
3634
+ icon = pc.yellow("~");
3635
+ statusText = pc.yellow("Partial");
3636
+ } else {
3637
+ icon = pc.red("\u2717");
3638
+ statusText = pc.red("Missing");
3639
+ }
3640
+ }
3091
3641
  const details = pc.dim(`(${item.details || ""})`);
3092
- checkLines.push(` ${icon} [${typeLabel}] ${pc.bold(item.name)}: ${item.satisfied ? pc.green("Detected") : pc.red("Missing")} ${details}`);
3642
+ checkLines.push(` ${icon} [${typeLabel}] ${pc.bold(item.name)}: ${statusText} ${details}`);
3093
3643
  }
3094
3644
  note(
3095
3645
  checkLines.join("\n"),
3096
3646
  `Prerequisite Evaluation: ${targetBundleDef.name} (${targetBundleDef.tier === "organization" ? "Organization Bundle" : "Prerequisites Required"})`
3097
3647
  );
3098
- if (!prereqEval.allSatisfied) {
3099
- if (isInteractive) {
3100
- const gateChoice = await select({
3101
- message: pc.yellow(`Prerequisites not fully satisfied for "${targetBundleDef.name}". How would you like to proceed?`),
3102
- options: [
3103
- {
3104
- value: "abort",
3105
- label: "\u{1F6D1} Abort and configure missing prerequisites (Recommended)",
3106
- hint: "exit and configure MCP servers, packages, or environment variables"
3107
- },
3108
- {
3109
- value: "brainstorming",
3110
- label: "\u{1F4A1} Install in Brainstorming Mode (Advisory & Spec generation only)",
3111
- hint: "runs in idea/planning mode without requiring live MCP tool connections"
3112
- },
3113
- {
3114
- value: "force",
3115
- label: "\u26A0\uFE0F Force install in Operational Mode anyway",
3116
- hint: "proceed despite missing prerequisites (may fail during runtime calls)"
3117
- }
3118
- ]
3119
- });
3120
- if (gateChoice === "abort" || typeof gateChoice !== "string") {
3121
- outro(pc.yellow("Installation aborted. Please configure required MCPs and environment variables, then retry."));
3122
- return;
3123
- }
3124
- if (gateChoice === "brainstorming") {
3125
- executionMode = "brainstorming";
3126
- note(pc.cyan('Switched execution mode to "brainstorming" (idea/spec fallback mode).'), "Mode Selected");
3127
- } else if (gateChoice === "force") {
3128
- executionMode = "operational";
3129
- note(pc.yellow('Proceeding in "operational" mode with missing prerequisites.'), "Warning");
3130
- }
3131
- } else {
3132
- if (options.mode === "brainstorming") {
3133
- executionMode = "brainstorming";
3134
- } else if (options.force || options.allowMissingPrereqs) {
3135
- executionMode = "operational";
3136
- } else {
3137
- const missingList = prereqEval.items.filter((i) => !i.satisfied).map((i) => `${i.type}:${i.name}`).join(", ");
3138
- outro(
3139
- pc.red(
3140
- `Error: Prerequisites not satisfied for "${targetBundleDef.name}".
3141
- Missing items: ${missingList}
3142
-
3143
- To install in fallback mode: agents add ${identifier} --mode brainstorming
3144
- To bypass prerequisite gate: agents add ${identifier} --allow-missing-prereqs`
3145
- )
3146
- );
3147
- process.exit(1);
3148
- }
3149
- }
3648
+ if (prereqEval.allSatisfied) {
3649
+ executionMode = options.mode || "operational";
3650
+ note(pc.green("All prerequisites are satisfied! Running in Fully Operational Mode."), "Prerequisites Ready");
3651
+ } else {
3652
+ executionMode = options.mode || "limited-operational";
3653
+ note(
3654
+ pc.cyan(
3655
+ "\u26A1 Adaptive Tooling: Limited Operational / Brainstorming Mode ready.\nYour Lead Orchestrator will automatically detect active tools and guide in-session configuration seamlessly."
3656
+ ),
3657
+ "Operational Envelope"
3658
+ );
3150
3659
  }
3151
3660
  }
3152
3661
  }
@@ -3259,6 +3768,14 @@ To use this bundle in Cline, Claude Code & others: agents update ${identifier} -
3259
3768
  "One library, every assistant"
3260
3769
  );
3261
3770
  }
3771
+ if (!options.dryRun && targetBundleDef?.tier === "organization") {
3772
+ note(
3773
+ pc.cyan(
3774
+ "\u{1F4A1} In-Session MCP Setup: Your Lead Orchestrator will automatically check your runtime tools\nand guide configuration of live browser automation, design tokens, or cloud APIs on demand."
3775
+ ),
3776
+ "Adaptive Tooling"
3777
+ );
3778
+ }
3262
3779
  outro(pc.green(`\u2714 Installed "${identifier}" successfully!`));
3263
3780
  } catch (err) {
3264
3781
  s.stop(pc.red("Failed resolution"));
@@ -3449,7 +3966,7 @@ Updates Available: ${report.outdatedCount > 0 ? pc.yellow(pc.bold(`${report.outd
3449
3966
  const unprojected = [];
3450
3967
  for (const rec of result.updated) {
3451
3968
  try {
3452
- const lf = await fs11.readJson(path13.join(rec.targetDir, "agents-united.json"));
3969
+ const lf = await fs12.readJson(path14.join(rec.targetDir, "agents-united.json"));
3453
3970
  if (!lf.fanout || lf.fanout.length === 0) unprojected.push(rec.name);
3454
3971
  } catch {
3455
3972
  }