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.
- package/README.md +54 -9
- package/dist/cli.js +706 -189
- package/dist/cli.js.map +1 -1
- package/package.json +2 -1
- package/registry/agents/orchestrator-business.md +26 -2
- package/registry/agents/orchestrator-design.md +25 -2
- package/registry/agents/orchestrator-engineering.md +25 -2
- package/registry/agents/orchestrator-marketing.md +86 -5
- package/registry/agents/orchestrator-research.md +26 -2
- package/registry/agents/orchestrator-security.md +25 -2
- package/registry/agents/orchestrator-system-architecture.md +25 -2
- package/registry/agents/orchestrator-universal.md +26 -2
- package/registry/agents/subagent-accessibility-lead.md +11 -4
- package/registry/agents/subagent-ai-model-architect.md +26 -5
- package/registry/agents/subagent-android-architect.md +11 -4
- package/registry/agents/subagent-appsec-penetration-tester.md +189 -0
- package/registry/agents/subagent-backend-architect.md +15 -7
- package/registry/agents/subagent-business-panel-experts.md +13 -9
- package/registry/agents/subagent-cloud-infrastructure-architect.md +126 -0
- package/registry/agents/subagent-cloud-security-architect.md +221 -0
- package/registry/agents/subagent-code-reviewer.md +12 -9
- package/registry/agents/subagent-compliance-grc-specialist.md +147 -0
- package/registry/agents/subagent-cross-platform-specialist.md +11 -4
- package/registry/agents/subagent-data-engineer.md +10 -4
- package/registry/agents/subagent-database-administrator.md +141 -0
- package/registry/agents/subagent-deep-research.md +26 -6
- package/registry/agents/subagent-design-ops-lead.md +12 -8
- package/registry/agents/subagent-design-researcher.md +12 -8
- package/registry/agents/subagent-design-systems-architect.md +14 -9
- package/registry/agents/subagent-designer-toolkit-expert.md +30 -10
- package/registry/agents/subagent-devops-engineer.md +31 -11
- package/registry/agents/subagent-distributed-systems-architect.md +11 -4
- package/registry/agents/subagent-e2e-tester.md +24 -4
- package/registry/agents/subagent-financial-analyst.md +119 -0
- package/registry/agents/subagent-finops-cost-engineer.md +98 -0
- package/registry/agents/subagent-frontend-architect.md +30 -10
- package/registry/agents/subagent-interaction-designer.md +12 -6
- package/registry/agents/subagent-ios-architect.md +9 -3
- package/registry/agents/subagent-legal-contract-analyst.md +108 -0
- package/registry/agents/subagent-lifecycle-email-specialist.md +9 -3
- package/registry/agents/subagent-literature-patent-analyst.md +78 -0
- package/registry/agents/subagent-market-intelligence-analyst.md +110 -0
- package/registry/agents/subagent-marketing-campaign-specialist.md +11 -5
- package/registry/agents/subagent-marketing-content-strategist.md +13 -8
- package/registry/agents/subagent-marketing-conversion-specialist.md +11 -6
- package/registry/agents/subagent-marketing-creative-designer.md +14 -6
- package/registry/agents/subagent-marketing-growth-strategist.md +10 -6
- package/registry/agents/subagent-ml-platform-engineer.md +27 -6
- package/registry/agents/subagent-operations-strategist.md +85 -0
- package/registry/agents/subagent-paid-acquisition-specialist.md +10 -3
- package/registry/agents/subagent-plg-strategist.md +10 -4
- package/registry/agents/subagent-prototype-tester.md +25 -7
- package/registry/agents/subagent-qa-automation-lead.md +27 -4
- package/registry/agents/subagent-repo-index.md +10 -8
- package/registry/agents/subagent-security-engineer.md +12 -4
- package/registry/agents/subagent-seo-specialist.md +10 -4
- package/registry/agents/subagent-socratic-mentor.md +11 -4
- package/registry/agents/subagent-statistical-analyst.md +132 -0
- package/registry/agents/subagent-sysops-sre-lead.md +26 -4
- package/registry/agents/subagent-system-architect.md +13 -7
- package/registry/agents/subagent-ui-designer.md +9 -4
- package/registry/agents/subagent-ux-strategist.md +11 -6
- package/registry/bundles.json +436 -65
- package/registry/skills/ab-test-setup/SKILL.md +6 -3
- package/registry/skills/accessibility-audit/SKILL.md +6 -3
- package/registry/skills/ad-attribution-modeling/SKILL.md +7 -3
- package/registry/skills/ad-creative-design/SKILL.md +7 -4
- package/registry/skills/ai-prototype-refactoring/SKILL.md +8 -4
- package/registry/skills/architecture-design/SKILL.md +5 -3
- package/registry/skills/azure-infrastructure-bicep/SKILL.md +8 -4
- package/registry/skills/backend-api-design/SKILL.md +6 -3
- package/registry/skills/chaos-engineering/SKILL.md +7 -4
- package/registry/skills/churn-prevention-playbook/SKILL.md +7 -3
- package/registry/skills/ci-cd-pipeline-automation/SKILL.md +7 -4
- package/registry/skills/clickable-prototype-spec/SKILL.md +6 -3
- package/registry/skills/code-refactoring/SKILL.md +6 -3
- package/registry/skills/component-library-management/SKILL.md +6 -3
- package/registry/skills/component-playground-setup/SKILL.md +6 -3
- package/registry/skills/content-calendar-strategy/SKILL.md +6 -3
- package/registry/skills/conversion-funnel-optimization/SKILL.md +6 -3
- package/registry/skills/copywriting-frameworks/SKILL.md +6 -3
- package/registry/skills/database-design/SKILL.md +6 -3
- package/registry/skills/dependency-management/SKILL.md +6 -3
- package/registry/skills/design-handoff-spec/SKILL.md +6 -3
- package/registry/skills/design-ops-workflow/SKILL.md +6 -3
- package/registry/skills/design-system-governance/SKILL.md +6 -3
- package/registry/skills/design-system-tokens/SKILL.md +6 -3
- package/registry/skills/design-tokens-management/SKILL.md +6 -3
- package/registry/skills/design-version-control/SKILL.md +6 -3
- package/registry/skills/diagnosing-bugs/SKILL.md +6 -4
- package/registry/skills/docker-deployment/SKILL.md +6 -3
- package/registry/skills/domain-modeling/SKILL.md +6 -4
- package/registry/skills/email-drip-sequences/SKILL.md +7 -3
- package/registry/skills/email-marketing-automation/SKILL.md +6 -3
- package/registry/skills/finishing-a-development-branch/SKILL.md +6 -3
- package/registry/skills/frontend-component-design/SKILL.md +6 -3
- package/registry/skills/git-guardrails/SKILL.md +7 -4
- package/registry/skills/google-ads-optimization/SKILL.md +7 -4
- package/registry/skills/graphql-schema-design/SKILL.md +6 -3
- package/registry/skills/grill-me/SKILL.md +14 -8
- package/registry/skills/grill-with-docs/SKILL.md +15 -9
- package/registry/skills/growth-experiment-design/SKILL.md +6 -3
- package/registry/skills/handoff/SKILL.md +7 -4
- package/registry/skills/hf-model-evaluation/SKILL.md +8 -4
- package/registry/skills/interaction-pattern-library/SKILL.md +6 -3
- package/registry/skills/interactive-prototype-builder/SKILL.md +50 -40
- package/registry/skills/local-llm-inference/SKILL.md +7 -4
- package/registry/skills/maestro-mobile-testing/SKILL.md +7 -4
- package/registry/skills/marketing-creative-design/SKILL.md +7 -3
- package/registry/skills/mcp-setup/SKILL.md +370 -0
- package/registry/skills/meta-ad-creative-testing/SKILL.md +7 -4
- package/registry/skills/micro-interaction-design/SKILL.md +6 -3
- package/registry/skills/microservices-architecture/SKILL.md +6 -3
- package/registry/skills/mobile-android-design/SKILL.md +7 -4
- package/registry/skills/mobile-first-design/SKILL.md +6 -3
- package/registry/skills/mobile-ios-design/SKILL.md +7 -4
- package/registry/skills/mobile-platform-offline-validate/SKILL.md +8 -4
- package/registry/skills/modal-serverless-python/SKILL.md +7 -4
- package/registry/skills/onboarding-cro/SKILL.md +7 -3
- package/registry/skills/paid-acquisition-ppc/SKILL.md +7 -3
- package/registry/skills/performance-optimization/SKILL.md +6 -3
- package/registry/skills/playwright-best-practices/SKILL.md +7 -4
- package/registry/skills/product-launch-playbook/SKILL.md +6 -3
- package/registry/skills/programmatic-seo/SKILL.md +7 -3
- package/registry/skills/rag-vector-pipeline/SKILL.md +8 -4
- package/registry/skills/react-best-practices/SKILL.md +7 -4
- package/registry/skills/receiving-code-review/SKILL.md +6 -3
- package/registry/skills/replicate-model-inference/SKILL.md +7 -4
- package/registry/skills/requesting-code-review/SKILL.md +6 -3
- package/registry/skills/responsive-design-audit/SKILL.md +6 -3
- package/registry/skills/runpod-gpu-orchestration/SKILL.md +8 -4
- package/registry/skills/schema-markup-strategy/SKILL.md +7 -3
- package/registry/skills/security-audit/SKILL.md +6 -3
- package/registry/skills/seo-audit/SKILL.md +6 -3
- package/registry/skills/signup-flow-cro/SKILL.md +6 -3
- package/registry/skills/social-media-campaign/SKILL.md +6 -3
- package/registry/skills/state-driven-ui-animation/SKILL.md +6 -3
- package/registry/skills/subagent-driven-development/SKILL.md +6 -3
- package/registry/skills/supabase-backend-architecture/SKILL.md +7 -4
- package/registry/skills/systematic-debugging/SKILL.md +6 -3
- package/registry/skills/technical-documentation/SKILL.md +6 -3
- package/registry/skills/technical-seo-audit/SKILL.md +7 -4
- package/registry/skills/telemetry-monitoring/SKILL.md +7 -4
- package/registry/skills/test-driven-development/SKILL.md +5 -3
- package/registry/skills/to-spec/SKILL.md +14 -9
- package/registry/skills/to-tickets/SKILL.md +6 -4
- package/registry/skills/turso-distributed-sqlite/SKILL.md +8 -4
- package/registry/skills/ui-component-spec/SKILL.md +6 -3
- package/registry/skills/usability-testing-protocol/SKILL.md +6 -3
- package/registry/skills/user-flow-mapping/SKILL.md +6 -3
- package/registry/skills/user-journey-mapping/SKILL.md +6 -3
- package/registry/skills/vector-database-design/SKILL.md +8 -4
- package/registry/skills/vercel-deploy-best-practices/SKILL.md +8 -4
- package/registry/skills/viral-referral-loops/SKILL.md +7 -3
- package/registry/workflows/workflow-agency-ad-creative-sprint.md +50 -0
- package/registry/workflows/workflow-agency-brand-design-system.md +50 -0
- package/registry/workflows/workflow-agency-client-pitch-proposal.md +50 -0
- package/registry/workflows/workflow-agency-cro-funnel-teardown.md +50 -0
- package/registry/workflows/workflow-agency-full-campaign.md +58 -0
- 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
|
|
8
|
-
import
|
|
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 (.
|
|
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" ? `~/.
|
|
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 =
|
|
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 = `.
|
|
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" ? `~/.
|
|
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
|
|
2438
|
+
var McpLocationRegistry = class _McpLocationRegistry {
|
|
2363
2439
|
/**
|
|
2364
|
-
*
|
|
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
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
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
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
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(
|
|
2410
|
-
const
|
|
2411
|
-
if (
|
|
2412
|
-
|
|
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
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
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
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
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
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
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
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
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
|
|
2475
|
-
|
|
2476
|
-
|
|
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
|
|
2479
|
-
if (await
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
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
|
-
|
|
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 =
|
|
2497
|
-
if (await
|
|
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 =
|
|
2501
|
-
if (await
|
|
2836
|
+
const pkgJsonPath = path13.join(cwd, "package.json");
|
|
2837
|
+
if (await fs11.pathExists(pkgJsonPath)) {
|
|
2502
2838
|
try {
|
|
2503
|
-
const pkg = await
|
|
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
|
-
|
|
2527
|
-
|
|
2862
|
+
path13.join(cwd, ".env.local"),
|
|
2863
|
+
path13.join(cwd, ".env")
|
|
2528
2864
|
];
|
|
2529
2865
|
for (const envFile of envFiles) {
|
|
2530
|
-
if (await
|
|
2866
|
+
if (await fs11.pathExists(envFile)) {
|
|
2531
2867
|
try {
|
|
2532
|
-
const content = await
|
|
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:
|
|
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
|
|
2565
|
-
status
|
|
2566
|
-
details
|
|
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) =>
|
|
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
|
-
|
|
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)}: ${
|
|
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 (
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
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
|
|
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
|
}
|