agent-enderun 1.11.2 → 1.11.4
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 +5 -5
- package/bin/validate-agent-army.js +0 -1
- package/dist/framework-mcp/src/index.js +11 -1
- package/dist/framework-mcp/src/index.js.map +1 -1
- package/dist/framework-mcp/src/tools/definitions.js +0 -10
- package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
- package/dist/framework-mcp/src/tools/index.js +0 -2
- package/dist/framework-mcp/src/tools/index.js.map +1 -1
- package/dist/framework-mcp/src/utils/compliance.d.ts +1 -1
- package/dist/framework-mcp/src/utils/compliance.js +68 -19
- package/dist/framework-mcp/src/utils/compliance.js.map +1 -1
- package/dist/src/cli/adapters/scaffold.d.ts +1 -1
- package/dist/src/cli/adapters/scaffold.js +8 -8
- package/dist/src/cli/adapters/scaffold.js.map +1 -1
- package/dist/src/cli/commands/check.js +25 -40
- package/dist/src/cli/commands/check.js.map +1 -1
- package/dist/src/cli/commands/contract.d.ts +3 -1
- package/dist/src/cli/commands/contract.js +8 -2
- package/dist/src/cli/commands/contract.js.map +1 -1
- package/dist/src/cli/commands/init/scaffold-ops.js +0 -2
- package/dist/src/cli/commands/init/scaffold-ops.js.map +1 -1
- package/dist/src/cli/commands/init.js +4 -3
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/orchestrate.js +10 -3
- package/dist/src/cli/commands/orchestrate.js.map +1 -1
- package/dist/src/cli/commands/status.js.map +1 -1
- package/dist/src/cli/index.js +14 -19
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/utils/compliance.d.ts +5 -1
- package/dist/src/cli/utils/compliance.js +90 -42
- package/dist/src/cli/utils/compliance.js.map +1 -1
- package/dist/src/cli/utils/ui.js +11 -11
- package/dist/src/cli/utils/ui.js.map +1 -1
- package/dist/src/modules/adapters/definitions.js +114 -113
- package/dist/src/modules/adapters/definitions.js.map +1 -1
- package/dist/src/modules/adapters/registry.d.ts +12 -0
- package/dist/src/modules/adapters/registry.js +19 -0
- package/dist/src/modules/adapters/registry.js.map +1 -0
- package/dist/src/modules/adapters/shared.js +5 -4
- package/dist/src/modules/adapters/shared.js.map +1 -1
- package/dist/src/modules/agents/definitions.d.ts +6 -6
- package/dist/src/modules/agents/definitions.js +49 -25
- package/dist/src/modules/agents/definitions.js.map +1 -1
- package/dist/src/modules/agents/registry/analyst.js +1 -1
- package/dist/src/modules/agents/registry/analyst.js.map +1 -1
- package/dist/src/modules/agents/registry/architect.js +1 -1
- package/dist/src/modules/agents/registry/architect.js.map +1 -1
- package/dist/src/modules/agents/registry/backend.js +1 -1
- package/dist/src/modules/agents/registry/backend.js.map +1 -1
- package/dist/src/modules/agents/registry/database.js +1 -1
- package/dist/src/modules/agents/registry/database.js.map +1 -1
- package/dist/src/modules/agents/registry/devops.js +1 -1
- package/dist/src/modules/agents/registry/devops.js.map +1 -1
- package/dist/src/modules/agents/registry/explorer.js +1 -1
- package/dist/src/modules/agents/registry/explorer.js.map +1 -1
- package/dist/src/modules/agents/registry/frontend.js +1 -1
- package/dist/src/modules/agents/registry/frontend.js.map +1 -1
- package/dist/src/modules/agents/registry/git.js +1 -1
- package/dist/src/modules/agents/registry/git.js.map +1 -1
- package/dist/src/modules/agents/registry/manager.js +1 -2
- package/dist/src/modules/agents/registry/manager.js.map +1 -1
- package/dist/src/modules/agents/registry/mobile.js +1 -1
- package/dist/src/modules/agents/registry/mobile.js.map +1 -1
- package/dist/src/modules/agents/registry/quality.js +1 -1
- package/dist/src/modules/agents/registry/quality.js.map +1 -1
- package/dist/src/modules/agents/registry/security.js +1 -1
- package/dist/src/modules/agents/registry/security.js.map +1 -1
- package/dist/src/shared/fs.js +4 -3
- package/dist/src/shared/fs.js.map +1 -1
- package/dist/tests/agents-definitions.test.js +2 -1
- package/dist/tests/agents-definitions.test.js.map +1 -1
- package/dist/tests/integration/hermes_locking.test.d.ts +1 -0
- package/dist/tests/integration/hermes_locking.test.js +62 -0
- package/dist/tests/integration/hermes_locking.test.js.map +1 -0
- package/dist/tests/orchestrate.test.js +9 -6
- package/dist/tests/orchestrate.test.js.map +1 -1
- package/framework-mcp/dist/index.js +11 -1
- package/framework-mcp/dist/tools/definitions.js +0 -10
- package/framework-mcp/dist/tools/index.js +0 -2
- package/framework-mcp/dist/utils/compliance.js +68 -19
- package/framework-mcp/node_modules/.package-lock.json +1179 -0
- package/framework-mcp/package-lock.json +1191 -0
- package/framework-mcp/package.json +2 -2
- package/framework-mcp/src/index.ts +13 -1
- package/framework-mcp/src/tools/definitions.ts +0 -10
- package/framework-mcp/src/tools/index.ts +0 -2
- package/framework-mcp/src/utils/compliance.ts +82 -24
- package/package.json +3 -4
- package/src/cli/adapters/scaffold.ts +9 -8
- package/src/cli/commands/check.ts +26 -48
- package/src/cli/commands/contract.ts +5 -2
- package/src/cli/commands/init/scaffold-ops.ts +0 -3
- package/src/cli/commands/init.ts +5 -3
- package/src/cli/commands/orchestrate.ts +12 -3
- package/src/cli/commands/status.ts +3 -2
- package/src/cli/index.ts +14 -20
- package/src/cli/utils/compliance.ts +101 -47
- package/src/cli/utils/ui.ts +11 -11
- package/src/modules/adapters/definitions.ts +82 -57
- package/src/modules/adapters/registry.ts +27 -0
- package/src/modules/adapters/shared.ts +5 -4
- package/src/modules/agents/definitions.ts +53 -24
- package/src/modules/agents/registry/analyst.ts +1 -1
- package/src/modules/agents/registry/architect.ts +1 -1
- package/src/modules/agents/registry/backend.ts +1 -1
- package/src/modules/agents/registry/database.ts +1 -1
- package/src/modules/agents/registry/devops.ts +1 -1
- package/src/modules/agents/registry/explorer.ts +1 -1
- package/src/modules/agents/registry/frontend.ts +1 -1
- package/src/modules/agents/registry/git.ts +1 -1
- package/src/modules/agents/registry/manager.ts +1 -2
- package/src/modules/agents/registry/mobile.ts +1 -1
- package/src/modules/agents/registry/quality.ts +1 -1
- package/src/modules/agents/registry/security.ts +1 -1
- package/src/shared/fs.ts +4 -3
- package/templates/standards/frontend-standards.md +7 -2
- package/templates/standards/governance-standards.md +27 -1
- package/templates/standards/logging-and-secrets.md +1 -1
- package/templates/standards/observability-standards.md +1 -1
- package/templates/standards/quality-standards.md +2 -1
- package/bin/enderun-dashboard.js +0 -25
- package/framework-mcp/src/tools/dashboard/start_dashboard.ts +0 -33
- package/src/cli/commands/dashboard/data-service.ts +0 -167
- package/src/cli/commands/dashboard/html-template.ts +0 -696
- package/src/cli/commands/dashboard/server.ts +0 -43
- package/src/cli/commands/dashboard.ts +0 -11
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import ts from "typescript";
|
|
3
4
|
|
|
4
5
|
interface ComplianceIssue {
|
|
5
6
|
file: string;
|
|
@@ -7,75 +8,128 @@ interface ComplianceIssue {
|
|
|
7
8
|
rule: string;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Enterprise Compliance Scanner (AST-Based)
|
|
13
|
+
* Scans the project source code for governance and discipline violations.
|
|
14
|
+
*/
|
|
15
|
+
export function scanProjectCompliance(targetDir: string = "src"): ComplianceIssue[] {
|
|
11
16
|
const issues: ComplianceIssue[] = [];
|
|
12
|
-
if (!fs.existsSync(
|
|
13
|
-
|
|
17
|
+
if (!fs.existsSync(targetDir)) return [];
|
|
18
|
+
|
|
19
|
+
const files = getAllFiles(targetDir);
|
|
14
20
|
|
|
15
21
|
for (const file of files) {
|
|
16
|
-
// Absolute skip for
|
|
22
|
+
// Absolute skip for critical framework and utility files to avoid self-flagging
|
|
17
23
|
if (file.includes("compliance") ||
|
|
18
24
|
file.includes("definitions") ||
|
|
19
|
-
file.includes("agents/registry") ||
|
|
20
|
-
file.includes("scaffold-ops.ts") ||
|
|
25
|
+
file.includes("agents/registry") ||
|
|
26
|
+
file.includes("scaffold-ops.ts") ||
|
|
21
27
|
file.includes("logger") ||
|
|
22
28
|
file.includes("errors") ||
|
|
23
29
|
file.includes("shared/fs")) continue;
|
|
24
30
|
|
|
25
31
|
const content = fs.readFileSync(file, "utf8");
|
|
26
|
-
|
|
32
|
+
|
|
33
|
+
// --- 1. AST-Based Analysis (For Language Rules) ---
|
|
34
|
+
const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);
|
|
35
|
+
|
|
36
|
+
const visit = (node: ts.Node) => {
|
|
37
|
+
// Rule: No console.log allowed (excluding UI and warn/error helpers)
|
|
38
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
39
|
+
const expression = node.expression;
|
|
40
|
+
const name = node.name.text;
|
|
41
|
+
if (ts.isIdentifier(expression) && expression.text === "console" && name === "log") {
|
|
42
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
43
|
+
issues.push({ file, line: line + 1, rule: "No console.log allowed (Use logger instead)" });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
47
|
+
// Rule: No 'any' type usage
|
|
48
|
+
if (ts.isTypeReferenceNode(node)) {
|
|
49
|
+
if (ts.isIdentifier(node.typeName) && node.typeName.text === "any") {
|
|
50
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
51
|
+
issues.push({ file, line: line + 1, rule: "Usage of 'any' type is forbidden" });
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (node.kind === ts.SyntaxKind.AnyKeyword) {
|
|
55
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
56
|
+
issues.push({ file, line: line + 1, rule: "Usage of 'any' keyword is forbidden" });
|
|
57
|
+
}
|
|
31
58
|
|
|
32
|
-
//
|
|
33
|
-
if (
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// 1. Console.log check - only if it's actual code
|
|
45
|
-
if (line.includes("console.log") && !isUIMessage) {
|
|
46
|
-
issues.push({ file, line: lineNum, rule: "No console.log allowed" });
|
|
59
|
+
// Rule: Zero UI Library Policy
|
|
60
|
+
if (ts.isImportDeclaration(node)) {
|
|
61
|
+
const moduleSpecifier = node.moduleSpecifier;
|
|
62
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
63
|
+
const forbiddenLibs = ["@chakra-ui", "mui", "@shadcn", "antd", "bootstrap"];
|
|
64
|
+
const lib = forbiddenLibs.find(l => moduleSpecifier.text.includes(l));
|
|
65
|
+
if (lib) {
|
|
66
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
67
|
+
issues.push({ file, line: line + 1, rule: `Forbidden UI library '${lib}' usage detected` });
|
|
68
|
+
}
|
|
69
|
+
}
|
|
47
70
|
}
|
|
48
71
|
|
|
49
|
-
//
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
72
|
+
// Rule: Raw fs mutation check (Use atomic utilities)
|
|
73
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
74
|
+
const prop = node.expression;
|
|
75
|
+
if (ts.isIdentifier(prop.expression) && prop.expression.text === "fs") {
|
|
76
|
+
if (["writeFileSync", "appendFileSync"].includes(prop.name.text)) {
|
|
77
|
+
// Skip if it's explicitly allowed (e.g. lock files)
|
|
78
|
+
const args = node.arguments;
|
|
79
|
+
let isLockFile = false;
|
|
80
|
+
|
|
81
|
+
if (args.length > 0) {
|
|
82
|
+
const firstArgText = args[0].getText(sourceFile).toLowerCase();
|
|
83
|
+
if (firstArgText.includes("lock")) {
|
|
84
|
+
isLockFile = true;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!isLockFile) {
|
|
89
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
90
|
+
issues.push({ file, line: line + 1, rule: "Use atomic utilities (writeTextFile) instead of raw fs mutations" });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
57
94
|
}
|
|
58
95
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
96
|
+
ts.forEachChild(node, visit);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
visit(sourceFile);
|
|
100
|
+
|
|
101
|
+
// --- 2. Pattern-Based Analysis (For Secrets & PII & Debt) ---
|
|
102
|
+
const lines = content.split("\n");
|
|
103
|
+
const piiKeywords = [
|
|
104
|
+
{ regex: /API_KEY\s*[:=]\s*['"][^'"]+['"]/i, msg: "Hardcoded API Key" },
|
|
105
|
+
{ regex: /SECRET\s*[:=]\s*['"][^'"]+['"]/i, msg: "Hardcoded Secret" },
|
|
106
|
+
{ regex: /PASSWORD\s*[:=]\s*['"][^'"]+['"]/i, msg: "Hardcoded Password" },
|
|
107
|
+
{ regex: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, msg: "PII Detected: Email Address" },
|
|
108
|
+
{ regex: /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/, msg: "PII Detected: Credit Card Pattern" }
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
lines.forEach((line, index) => {
|
|
112
|
+
const lineNum = index + 1;
|
|
113
|
+
const trimmedLine = line.trim();
|
|
114
|
+
|
|
115
|
+
if (trimmedLine.startsWith("//") || trimmedLine.startsWith("*")) return;
|
|
116
|
+
|
|
117
|
+
// PII & Secret Guard
|
|
118
|
+
for (const { regex, msg } of piiKeywords) {
|
|
119
|
+
if (regex.test(line)) {
|
|
120
|
+
// Allow emails in specific files
|
|
121
|
+
if (msg.includes("Email") && (file.endsWith("README.md") || file.endsWith("package.json") || file.includes("CONTRIBUTING"))) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
issues.push({ file, line: lineNum, rule: `Corporate Compliance Breach: ${msg}` });
|
|
125
|
+
}
|
|
62
126
|
}
|
|
63
127
|
|
|
64
|
-
//
|
|
128
|
+
// Technical Debt (TODO/FIXME)
|
|
65
129
|
if (/\b(TODO|FIXME)\b/i.test(line)) {
|
|
66
130
|
issues.push({ file, line: lineNum, rule: "Unresolved Technical Debt (TODO/FIXME) found" });
|
|
67
131
|
}
|
|
68
|
-
|
|
69
|
-
// 5. Raw fs write check (Atomic safety enforcement)
|
|
70
|
-
if ((line.includes("fs.writeFileSync") || line.includes("fs.appendFileSync")) &&
|
|
71
|
-
!file.includes("src/shared/fs.ts") && // Ignore the utility itself
|
|
72
|
-
!line.includes(".lock") && // Allow lock files
|
|
73
|
-
!line.includes("lockPath") && // Allow lock path variables
|
|
74
|
-
!file.includes("bin/")) { // Ignore standalone binary scripts
|
|
75
|
-
issues.push({ file, line: lineNum, rule: "Use internal atomic utilities (writeTextFile) instead of raw fs" });
|
|
76
|
-
}
|
|
77
132
|
});
|
|
78
|
-
|
|
79
133
|
}
|
|
80
134
|
return issues;
|
|
81
135
|
}
|
package/src/cli/utils/ui.ts
CHANGED
|
@@ -10,8 +10,8 @@ export const UI = {
|
|
|
10
10
|
* Renders a strategic intent block similar to Gemini CLI's topic updates.
|
|
11
11
|
*/
|
|
12
12
|
intent: (title: string, intent: string) => {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
process.stdout.write(`\n${chalk.bold.cyan(title)}:\n`);
|
|
14
|
+
process.stdout.write(`${chalk.italic.gray(` ${intent}`)}\n\n`);
|
|
15
15
|
},
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -21,39 +21,39 @@ export const UI = {
|
|
|
21
21
|
const width = process.stdout.columns || 80;
|
|
22
22
|
const line = "─".repeat(Math.max(0, width - 2));
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
process.stdout.write(chalk.gray(`╭${line}╮`) + "\n");
|
|
25
25
|
const padding = Math.max(0, width - agentName.length - 27);
|
|
26
|
-
|
|
26
|
+
process.stdout.write(`${chalk.gray("│")} ${chalk.bold.yellow("≡")} ${chalk.white(`Running Agent: ${chalk.bold.green(agentName)}...`)} ${chalk.gray("(ctrl+o to expand)".padStart(padding))} ${chalk.gray("│")}\n`);
|
|
27
27
|
if (action) {
|
|
28
28
|
const paddingAction = Math.max(0, width - action.length - 6);
|
|
29
|
-
|
|
29
|
+
process.stdout.write(`${chalk.gray("│")} ${chalk.blue("!")} ${chalk.cyan(action)} ${" ".repeat(paddingAction)} ${chalk.gray("│")}\n`);
|
|
30
30
|
}
|
|
31
31
|
if (details) {
|
|
32
32
|
const paddingDetails = Math.max(0, width - details.length - 7);
|
|
33
|
-
|
|
33
|
+
process.stdout.write(`${chalk.gray("│")} ${chalk.gray(details.slice(0, width - 10))} ${" ".repeat(paddingDetails)} ${chalk.gray("│")}\n`);
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
process.stdout.write(chalk.gray(`╰${line}╯`) + "\n");
|
|
36
36
|
},
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Renders a success status message.
|
|
40
40
|
*/
|
|
41
41
|
success: (msg: string) => {
|
|
42
|
-
|
|
42
|
+
process.stdout.write(`${chalk.bold.green("✅")} ${msg}\n`);
|
|
43
43
|
},
|
|
44
44
|
|
|
45
45
|
/**
|
|
46
46
|
* Renders an error status message.
|
|
47
47
|
*/
|
|
48
48
|
error: (msg: string) => {
|
|
49
|
-
|
|
49
|
+
process.stderr.write(`${chalk.bold.red("❌")} ${chalk.red(msg)}\n`);
|
|
50
50
|
},
|
|
51
51
|
|
|
52
52
|
/**
|
|
53
53
|
* Renders a warning status message.
|
|
54
54
|
*/
|
|
55
55
|
warning: (msg: string) => {
|
|
56
|
-
|
|
56
|
+
process.stdout.write(`${chalk.bold.yellow("⚠️")} ${chalk.yellow(msg)}\n`);
|
|
57
57
|
},
|
|
58
58
|
|
|
59
59
|
/**
|
|
@@ -61,6 +61,6 @@ export const UI = {
|
|
|
61
61
|
*/
|
|
62
62
|
divider: () => {
|
|
63
63
|
const width = process.stdout.columns || 80;
|
|
64
|
-
|
|
64
|
+
process.stdout.write(chalk.gray("─".repeat(width)) + "\n");
|
|
65
65
|
}
|
|
66
66
|
};
|
|
@@ -3,13 +3,14 @@ import type { AdapterConfig, AdapterId } from "./types.js";
|
|
|
3
3
|
import { addMcpServerToClaude, findClaudeConfigPath } from "../../cli/utils/claude.js";
|
|
4
4
|
import { writeJsonFile } from "../../shared/fs.js";
|
|
5
5
|
import { registerGlobalAntigravityPlugins } from "./shared.js";
|
|
6
|
-
import {
|
|
6
|
+
import { registry } from "./registry.js";
|
|
7
|
+
import { UI } from "../../cli/utils/ui.js";
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
// ─── Register Core Adapters ──────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
// ♊ Gemini
|
|
12
|
+
registry.register(
|
|
13
|
+
{
|
|
13
14
|
id: "gemini",
|
|
14
15
|
frameworkDir: ".gemini",
|
|
15
16
|
shimFile: "GEMINI.md",
|
|
@@ -17,10 +18,20 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
17
18
|
role: "commander",
|
|
18
19
|
templateDir: ".enderun",
|
|
19
20
|
nestedDirs: ["agents", "rules"],
|
|
20
|
-
agentsDir: ".gemini/agents",
|
|
21
|
+
agentsDir: ".gemini/agents",
|
|
21
22
|
agentsExt: ".md"
|
|
22
23
|
},
|
|
23
|
-
|
|
24
|
+
(projectRoot, mcpBlock) => {
|
|
25
|
+
const frameworkDir = ".gemini";
|
|
26
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp.json"), mcpBlock);
|
|
27
|
+
UI.success(`Gemini MCP registered → ${frameworkDir}/mcp.json`);
|
|
28
|
+
registerGlobalAntigravityPlugins(mcpBlock);
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// 🚀 Claude
|
|
33
|
+
registry.register(
|
|
34
|
+
{
|
|
24
35
|
id: "claude",
|
|
25
36
|
frameworkDir: ".claude",
|
|
26
37
|
shimFile: "CLAUDE.md",
|
|
@@ -31,7 +42,24 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
31
42
|
agentsDir: ".claude/agents",
|
|
32
43
|
agentsExt: ".md"
|
|
33
44
|
},
|
|
34
|
-
|
|
45
|
+
(projectRoot, mcpBlock) => {
|
|
46
|
+
const configPath = findClaudeConfigPath();
|
|
47
|
+
if (configPath) {
|
|
48
|
+
const block = mcpBlock as { mcpServers: Record<string, unknown> };
|
|
49
|
+
const mcpEntry = block.mcpServers["agent-enderun"] as Record<string, unknown>;
|
|
50
|
+
const ok = addMcpServerToClaude(configPath, "agent-enderun", mcpEntry);
|
|
51
|
+
if (ok) UI.success(`Claude MCP registered → ${configPath}`);
|
|
52
|
+
}
|
|
53
|
+
const frameworkDir = ".claude";
|
|
54
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
55
|
+
writeJsonFile(path.join(projectRoot, ".mcp.json"), mcpBlock);
|
|
56
|
+
UI.success("Claude Code Project MCP → .mcp.json");
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// 🤖 Grok
|
|
61
|
+
registry.register(
|
|
62
|
+
{
|
|
35
63
|
id: "grok",
|
|
36
64
|
frameworkDir: ".grok",
|
|
37
65
|
shimFile: "GROK.md",
|
|
@@ -42,7 +70,16 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
42
70
|
agentsDir: ".grok/agents",
|
|
43
71
|
agentsExt: ".md"
|
|
44
72
|
},
|
|
45
|
-
|
|
73
|
+
(projectRoot, mcpBlock) => {
|
|
74
|
+
const frameworkDir = ".grok";
|
|
75
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
76
|
+
UI.success(`Grok MCP → ${frameworkDir}/mcp_config.json`);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// ✍️ Cursor
|
|
81
|
+
registry.register(
|
|
82
|
+
{
|
|
46
83
|
id: "cursor",
|
|
47
84
|
frameworkDir: ".cursor",
|
|
48
85
|
shimFile: "CURSOR.md",
|
|
@@ -53,7 +90,16 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
53
90
|
agentsDir: ".cursor/rules",
|
|
54
91
|
agentsExt: ".mdc"
|
|
55
92
|
},
|
|
56
|
-
|
|
93
|
+
(projectRoot, mcpBlock) => {
|
|
94
|
+
const frameworkDir = ".cursor";
|
|
95
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp.json"), mcpBlock);
|
|
96
|
+
UI.success(`Cursor IDE Project MCP → ${frameworkDir}/mcp.json`);
|
|
97
|
+
}
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// 💡 Codex (Copilot)
|
|
101
|
+
registry.register(
|
|
102
|
+
{
|
|
57
103
|
id: "codex",
|
|
58
104
|
frameworkDir: ".agents",
|
|
59
105
|
shimFile: "copilot-instructions.md",
|
|
@@ -64,7 +110,18 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
64
110
|
agentsDir: ".agents/instructions",
|
|
65
111
|
agentsExt: ".md"
|
|
66
112
|
},
|
|
67
|
-
|
|
113
|
+
(projectRoot, mcpBlock) => {
|
|
114
|
+
const frameworkDir = ".agents";
|
|
115
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
116
|
+
writeJsonFile(path.join(projectRoot, ".vscode/mcp.json"), mcpBlock);
|
|
117
|
+
writeJsonFile(path.join(projectRoot, ".mcp.json"), mcpBlock);
|
|
118
|
+
UI.success("GitHub Copilot Project MCP → .vscode/mcp.json & .mcp.json");
|
|
119
|
+
}
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
// 🛸 Antigravity
|
|
123
|
+
registry.register(
|
|
124
|
+
{
|
|
68
125
|
id: "antigravity-cli",
|
|
69
126
|
frameworkDir: ".antigravity",
|
|
70
127
|
shimFile: "AGENTS.md",
|
|
@@ -74,53 +131,21 @@ export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = {
|
|
|
74
131
|
nestedDirs: ["agents", "plugins", "rules"],
|
|
75
132
|
agentsDir: ".antigravity/agents",
|
|
76
133
|
agentsExt: ".md"
|
|
134
|
+
},
|
|
135
|
+
(projectRoot, mcpBlock) => {
|
|
136
|
+
const frameworkDir = ".antigravity";
|
|
137
|
+
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
138
|
+
UI.success(`Antigravity CLI MCP → ${frameworkDir}/mcp_config.json`);
|
|
139
|
+
registerGlobalAntigravityPlugins(mcpBlock);
|
|
77
140
|
}
|
|
78
|
-
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Mapped Adapter Configurations
|
|
145
|
+
*/
|
|
146
|
+
export const ADAPTER_CONFIGS: Record<AdapterId, AdapterConfig> = registry.getConfigs();
|
|
79
147
|
|
|
80
148
|
/**
|
|
81
149
|
* Post-Initialization Handlers for specific adapters
|
|
82
150
|
*/
|
|
83
|
-
export const POST_INIT_HANDLERS: Record<AdapterId, (projectRoot: string, mcpBlock: unknown) => void> =
|
|
84
|
-
gemini: (projectRoot, mcpBlock) => {
|
|
85
|
-
const frameworkDir = ADAPTER_CONFIGS.gemini.frameworkDir;
|
|
86
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp.json"), mcpBlock);
|
|
87
|
-
console.warn(`✅ Gemini MCP registered → ${frameworkDir}/mcp.json`);
|
|
88
|
-
registerGlobalAntigravityPlugins(mcpBlock);
|
|
89
|
-
},
|
|
90
|
-
claude: (projectRoot, mcpBlock) => {
|
|
91
|
-
const configPath = findClaudeConfigPath();
|
|
92
|
-
if (configPath) {
|
|
93
|
-
const block = mcpBlock as { mcpServers: Record<string, unknown> };
|
|
94
|
-
const mcpEntry = block.mcpServers["agent-enderun"] as Record<string, unknown>;
|
|
95
|
-
const ok = addMcpServerToClaude(configPath, "agent-enderun", mcpEntry);
|
|
96
|
-
if (ok) console.warn(`✅ Claude MCP registered → ${configPath}`);
|
|
97
|
-
}
|
|
98
|
-
const frameworkDir = ADAPTER_CONFIGS.claude.frameworkDir;
|
|
99
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
100
|
-
writeJsonFile(path.join(projectRoot, ".mcp.json"), mcpBlock);
|
|
101
|
-
console.warn("✅ Claude Code Project MCP → .mcp.json");
|
|
102
|
-
},
|
|
103
|
-
grok: (projectRoot, mcpBlock) => {
|
|
104
|
-
const frameworkDir = ADAPTER_CONFIGS.grok.frameworkDir;
|
|
105
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
106
|
-
console.warn(`✅ Grok MCP → ${frameworkDir}/mcp_config.json`);
|
|
107
|
-
},
|
|
108
|
-
cursor: (projectRoot, mcpBlock) => {
|
|
109
|
-
const frameworkDir = ADAPTER_CONFIGS.cursor.frameworkDir;
|
|
110
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp.json"), mcpBlock);
|
|
111
|
-
console.warn(`✅ Cursor IDE Project MCP → ${frameworkDir}/mcp.json`);
|
|
112
|
-
},
|
|
113
|
-
codex: (projectRoot, mcpBlock) => {
|
|
114
|
-
const frameworkDir = ADAPTER_CONFIGS.codex.frameworkDir;
|
|
115
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
116
|
-
writeJsonFile(path.join(projectRoot, ".vscode/mcp.json"), mcpBlock);
|
|
117
|
-
writeJsonFile(path.join(projectRoot, ".mcp.json"), mcpBlock);
|
|
118
|
-
console.warn("✅ GitHub Copilot Project MCP → .vscode/mcp.json & .mcp.json");
|
|
119
|
-
},
|
|
120
|
-
"antigravity-cli": (projectRoot, mcpBlock) => {
|
|
121
|
-
const frameworkDir = ADAPTER_CONFIGS["antigravity-cli"].frameworkDir;
|
|
122
|
-
writeJsonFile(path.join(projectRoot, frameworkDir, "mcp_config.json"), mcpBlock);
|
|
123
|
-
console.warn(`✅ Antigravity CLI MCP → ${frameworkDir}/mcp_config.json`);
|
|
124
|
-
registerGlobalAntigravityPlugins(mcpBlock);
|
|
125
|
-
}
|
|
126
|
-
};
|
|
151
|
+
export const POST_INIT_HANDLERS: Record<AdapterId, (projectRoot: string, mcpBlock: unknown) => void> = registry.getHandlers();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { AdapterId, AdapterConfig } from "./types.js";
|
|
2
|
+
|
|
3
|
+
type PostInitHandler = (projectRoot: string, mcpBlock: unknown) => void;
|
|
4
|
+
|
|
5
|
+
class AdapterRegistry {
|
|
6
|
+
private configs: Map<string, AdapterConfig> = new Map();
|
|
7
|
+
private handlers: Map<string, PostInitHandler> = new Map();
|
|
8
|
+
|
|
9
|
+
register(config: AdapterConfig, handler: PostInitHandler) {
|
|
10
|
+
this.configs.set(config.id, config);
|
|
11
|
+
this.handlers.set(config.id, handler);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getConfigs(): Record<string, AdapterConfig> {
|
|
15
|
+
return Object.fromEntries(this.configs);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
getHandlers(): Record<string, PostInitHandler> {
|
|
19
|
+
return Object.fromEntries(this.handlers);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
getIds(): AdapterId[] {
|
|
23
|
+
return Array.from(this.configs.keys()) as AdapterId[];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const registry = new AdapterRegistry();
|
|
@@ -6,6 +6,7 @@ import { writeJsonFile, writeTextFile } from "../../shared/fs.js";
|
|
|
6
6
|
import { ALL_AGENTS, toAntigravityJson } from "../agents/definitions.js";
|
|
7
7
|
import { CORE_SKILLS } from "../skills/definitions.js";
|
|
8
8
|
import { getPackageRoot } from "../../cli/utils/pkg.js";
|
|
9
|
+
import { logger } from "../../shared/logger.js";
|
|
9
10
|
|
|
10
11
|
export function registerGlobalAntigravityPlugins(mcpBlock: unknown): void {
|
|
11
12
|
// Allow overriding via env var for different OS/Gemini CLI versions
|
|
@@ -20,7 +21,7 @@ export function registerGlobalAntigravityPlugins(mcpBlock: unknown): void {
|
|
|
20
21
|
fs.mkdirSync(globalDir, { recursive: true });
|
|
21
22
|
writeJsonFile(path.join(globalDir, "mcp.json"), mcpBlock);
|
|
22
23
|
writeJsonFile(path.join(globalDir, "mcp_config.json"), mcpBlock);
|
|
23
|
-
|
|
24
|
+
logger.info(`Antigravity MCP registered → ${globalDir}/`);
|
|
24
25
|
|
|
25
26
|
// Global Plugin configuration under plugins/agent-enderun/
|
|
26
27
|
const globalPluginDir = path.join(globalDir, "plugins/agent-enderun");
|
|
@@ -103,17 +104,17 @@ ${ag.instructions.rules.map(r => `- ${r}`).join("\n")}
|
|
|
103
104
|
// Scaffold optional empty hooks.json
|
|
104
105
|
writeJsonFile(path.join(globalPluginDir, "hooks.json"), {});
|
|
105
106
|
|
|
106
|
-
|
|
107
|
+
logger.info(`Antigravity Plugin registered → ${globalPluginDir}/`);
|
|
107
108
|
|
|
108
109
|
try {
|
|
109
110
|
execSync(`agy plugin install "${globalPluginDir}"`, { stdio: "ignore" });
|
|
110
|
-
|
|
111
|
+
logger.info("Antigravity Plugin installed in CLI.");
|
|
111
112
|
} catch {
|
|
112
113
|
// Ignore if agy is not in PATH or fails
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
} catch (e) {
|
|
116
|
-
|
|
117
|
+
logger.warn(`Failed to register plugin/MCP in ${globalDir}`, e);
|
|
117
118
|
}
|
|
118
119
|
}
|
|
119
120
|
}
|