atabey-mcp 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{constants.js → framework-mcp/src/constants.js} +1 -1
- package/dist/{index.js → framework-mcp/src/index.js} +29 -5
- package/dist/framework-mcp/src/resources/index.js +58 -0
- package/dist/{tools → framework-mcp/src/tools}/control_plane/locking.js +3 -3
- package/dist/{tools → framework-mcp/src/tools}/control_plane/registry.js +3 -2
- package/dist/{tools → framework-mcp/src/tools}/definitions.js +33 -1
- package/dist/{tools → framework-mcp/src/tools}/file_system/batch_surgical_edit.js +8 -3
- package/dist/{tools → framework-mcp/src/tools}/file_system/patch_file.js +8 -3
- package/dist/{tools → framework-mcp/src/tools}/file_system/read_file.js +3 -3
- package/dist/{tools → framework-mcp/src/tools}/file_system/replace_text.js +8 -3
- package/dist/{tools → framework-mcp/src/tools}/file_system/write_file.js +10 -5
- package/dist/{tools → framework-mcp/src/tools}/framework/audit_deps.js +2 -2
- package/dist/{tools → framework-mcp/src/tools}/framework/run_tests.js +2 -2
- package/dist/framework-mcp/src/tools/framework/submit_plan.js +13 -0
- package/dist/{tools → framework-mcp/src/tools}/framework/update_memory.js +1 -1
- package/dist/{tools → framework-mcp/src/tools}/index.js +2 -0
- package/dist/{tools → framework-mcp/src/tools}/memory/get_insights.js +1 -1
- package/dist/{tools → framework-mcp/src/tools}/messaging/log_action.js +1 -1
- package/dist/{tools → framework-mcp/src/tools}/messaging/send_message.js +5 -5
- package/dist/{tools → framework-mcp/src/tools}/observability/check_ports.js +1 -1
- package/dist/{tools → framework-mcp/src/tools}/quality/check_lint.js +2 -2
- package/dist/{tools → framework-mcp/src/tools}/search/get_gaps.js +1 -1
- package/dist/{tools → framework-mcp/src/tools}/search/grep_search.js +3 -3
- package/dist/framework-mcp/src/utils/compliance.js +231 -0
- package/dist/framework-mcp/src/utils/permissions.js +71 -0
- package/dist/src/cli/adapters/core.js +78 -0
- package/dist/src/cli/adapters/index.js +5 -0
- package/dist/src/cli/adapters/paths.js +101 -0
- package/dist/src/cli/adapters/scaffold.js +71 -0
- package/dist/src/cli/adapters/utils.js +75 -0
- package/dist/src/cli/commands/approve.js +63 -0
- package/dist/src/cli/commands/check.js +181 -0
- package/dist/src/cli/commands/compliance.js +50 -0
- package/dist/src/cli/commands/contract.js +50 -0
- package/dist/src/cli/commands/dashboard.js +123 -0
- package/dist/src/cli/commands/explorer.js +42 -0
- package/dist/src/cli/commands/git.js +40 -0
- package/dist/src/cli/commands/init/create-agent.js +58 -0
- package/dist/src/cli/commands/init/scaffold-core.js +112 -0
- package/dist/src/cli/commands/init/scaffold-docs.js +34 -0
- package/dist/src/cli/commands/init/scaffold-ops.js +80 -0
- package/dist/src/cli/commands/init/scaffold-standards.js +67 -0
- package/dist/src/cli/commands/init.js +167 -0
- package/dist/src/cli/commands/knowledge.js +42 -0
- package/dist/src/cli/commands/lint.js +22 -0
- package/dist/src/cli/commands/log.js +10 -0
- package/dist/src/cli/commands/memory.js +4 -0
- package/dist/src/cli/commands/orchestrate.js +159 -0
- package/dist/src/cli/commands/plan.js +117 -0
- package/dist/src/cli/commands/script.js +19 -0
- package/dist/src/cli/commands/security.js +36 -0
- package/dist/src/cli/commands/status.js +97 -0
- package/dist/src/cli/commands/trace.js +109 -0
- package/dist/src/cli/index.js +338 -0
- package/dist/src/cli/shims.js +66 -0
- package/dist/src/cli/utils/claude.js +56 -0
- package/dist/src/cli/utils/compliance.js +173 -0
- package/dist/src/cli/utils/config-schema.js +42 -0
- package/dist/src/cli/utils/fs.js +137 -0
- package/dist/src/cli/utils/i18n.js +30 -0
- package/dist/src/cli/utils/memory.js +276 -0
- package/dist/src/cli/utils/pkg.js +282 -0
- package/dist/src/cli/utils/schemas.js +19 -0
- package/dist/src/cli/utils/string.js +49 -0
- package/dist/src/cli/utils/time.js +27 -0
- package/dist/src/cli/utils/ui.js +58 -0
- package/dist/src/contracts/index.js +1 -0
- package/dist/src/contracts/tasks.js +20 -0
- package/dist/src/dashboard/vite.config.js +15 -0
- package/dist/src/modules/adapters/definitions.js +140 -0
- package/dist/src/modules/adapters/registry.js +18 -0
- package/dist/src/modules/adapters/shared.js +104 -0
- package/dist/src/modules/adapters/types.js +1 -0
- package/dist/src/modules/agents/definitions.js +457 -0
- package/dist/src/modules/agents/registry/analyst.js +39 -0
- package/dist/src/modules/agents/registry/architect.js +42 -0
- package/dist/src/modules/agents/registry/backend.js +49 -0
- package/dist/src/modules/agents/registry/database.js +45 -0
- package/dist/src/modules/agents/registry/devops.js +45 -0
- package/dist/src/modules/agents/registry/explorer.js +36 -0
- package/dist/src/modules/agents/registry/frontend.js +51 -0
- package/dist/src/modules/agents/registry/git.js +36 -0
- package/dist/src/modules/agents/registry/manager.js +53 -0
- package/dist/src/modules/agents/registry/mobile.js +39 -0
- package/dist/src/modules/agents/registry/native.js +39 -0
- package/dist/src/modules/agents/registry/quality.js +41 -0
- package/dist/src/modules/agents/registry/security.js +43 -0
- package/dist/src/modules/agents/types.js +1 -0
- package/dist/src/modules/engines/evaluation-engine.js +102 -0
- package/dist/src/modules/engines/health-engine.js +49 -0
- package/dist/src/modules/engines/planning-engine.js +78 -0
- package/dist/src/modules/engines/risk-engine.js +105 -0
- package/dist/src/modules/engines/routing-engine.js +73 -0
- package/dist/src/modules/engines/types.js +1 -0
- package/dist/src/modules/skills/definitions.js +70 -0
- package/dist/src/shared/constants.js +186 -0
- package/dist/src/shared/errors.js +68 -0
- package/dist/src/shared/fs.js +51 -0
- package/dist/src/shared/logger.js +116 -0
- package/dist/src/shared/storage.js +207 -0
- package/dist/src/shared/types.js +12 -0
- package/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/declarations.d.ts +3 -1
- package/src/index.ts +31 -4
- package/src/resources/index.ts +65 -0
- package/src/tools/control_plane/locking.ts +3 -3
- package/src/tools/control_plane/registry.ts +3 -2
- package/src/tools/definitions.ts +33 -1
- package/src/tools/file_system/batch_surgical_edit.ts +11 -3
- package/src/tools/file_system/patch_file.ts +10 -3
- package/src/tools/file_system/read_file.ts +3 -3
- package/src/tools/file_system/replace_text.ts +10 -3
- package/src/tools/file_system/write_file.ts +12 -5
- package/src/tools/framework/audit_deps.ts +2 -2
- package/src/tools/framework/run_tests.ts +2 -2
- package/src/tools/framework/submit_plan.ts +26 -0
- package/src/tools/framework/update_memory.ts +1 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/memory/get_insights.ts +1 -1
- package/src/tools/messaging/log_action.ts +1 -1
- package/src/tools/messaging/send_message.ts +5 -5
- package/src/tools/observability/check_ports.ts +1 -1
- package/src/tools/quality/check_lint.ts +2 -2
- package/src/tools/search/get_gaps.ts +1 -1
- package/src/tools/search/grep_search.ts +3 -3
- package/src/tools/types.ts +1 -1
- package/src/utils/compliance.ts +181 -5
- package/src/utils/permissions.ts +88 -0
- package/tsconfig.json +1 -2
- package/dist/utils/compliance.js +0 -78
- /package/dist/{tools → framework-mcp/src/tools}/framework/get_status.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/framework/orchestrate.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/framework/update_contract_hash.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/memory/read_memory.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/observability/get_health.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/search/get_map.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/search/list_dir.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/shell/run_command.js +0 -0
- /package/dist/{tools → framework-mcp/src/tools}/types.js +0 -0
- /package/dist/{utils → framework-mcp/src/utils}/cli.js +0 -0
- /package/dist/{utils → framework-mcp/src/utils}/fs.js +0 -0
- /package/dist/{utils → framework-mcp/src/utils}/metrics.js +0 -0
- /package/dist/{utils → framework-mcp/src/utils}/security.js +0 -0
|
@@ -46,7 +46,7 @@ export const NATIVE_AGENT_PATHS = {
|
|
|
46
46
|
cursor: ".cursor/rules",
|
|
47
47
|
codex: ".agents/instructions",
|
|
48
48
|
grok: ".grok",
|
|
49
|
-
"antigravity-cli": ".
|
|
49
|
+
"antigravity-cli": ".agents/agents",
|
|
50
50
|
};
|
|
51
51
|
// ─── Backward-compatible aliases ──────────────────────────────────────────
|
|
52
52
|
export const CORE_FRAMEWORK_DIR = FRAMEWORK.CORE_DIR;
|
|
@@ -4,8 +4,9 @@ import path from "path";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
7
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
8
8
|
import { TOOLS, toolHandlers } from "./tools/index.js";
|
|
9
|
+
import { RESOURCES, handleReadResource } from "./resources/index.js";
|
|
9
10
|
// ─── Server Setup ─────────────────────────────────────────────────
|
|
10
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
11
12
|
// Robustly find package.json by walking up from __dirname
|
|
@@ -28,6 +29,7 @@ const server = new Server({
|
|
|
28
29
|
}, {
|
|
29
30
|
capabilities: {
|
|
30
31
|
tools: {},
|
|
32
|
+
resources: {},
|
|
31
33
|
},
|
|
32
34
|
});
|
|
33
35
|
// Basic Schema Validator for Required Fields
|
|
@@ -51,6 +53,28 @@ server.setRequestHandler(ListToolsRequestSchema, async (request) => {
|
|
|
51
53
|
}
|
|
52
54
|
return { tools: TOOLS };
|
|
53
55
|
});
|
|
56
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
57
|
+
return { resources: RESOURCES };
|
|
58
|
+
});
|
|
59
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
60
|
+
const uri = request.params.uri;
|
|
61
|
+
try {
|
|
62
|
+
const content = await handleReadResource(uri);
|
|
63
|
+
return {
|
|
64
|
+
contents: [
|
|
65
|
+
{
|
|
66
|
+
uri,
|
|
67
|
+
mimeType: "text/markdown",
|
|
68
|
+
text: content,
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
throw new Error(`Failed to read resource: ${message}`, { cause: error });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
54
78
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
55
79
|
const req = request;
|
|
56
80
|
const { name, arguments: args } = req.params;
|
|
@@ -65,15 +89,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
65
89
|
if (!handler) {
|
|
66
90
|
return {
|
|
67
91
|
isError: true,
|
|
68
|
-
content: [{ type: "text", text:
|
|
92
|
+
content: [{ type: "text", text: `[ERROR] Unknown tool: ${name}` }],
|
|
69
93
|
};
|
|
70
94
|
}
|
|
71
|
-
//
|
|
95
|
+
// [SECURITY] Runtime Validation
|
|
72
96
|
const validationError = validateArgs(name, args || {});
|
|
73
97
|
if (validationError) {
|
|
74
98
|
return {
|
|
75
99
|
isError: true,
|
|
76
|
-
content: [{ type: "text", text:
|
|
100
|
+
content: [{ type: "text", text: `[ERROR] Validation Error: ${validationError}` }],
|
|
77
101
|
};
|
|
78
102
|
}
|
|
79
103
|
return await handler(projectRoot, args || {});
|
|
@@ -82,7 +106,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
82
106
|
const message = error instanceof Error ? error.message : "Unknown error occurred";
|
|
83
107
|
return {
|
|
84
108
|
isError: true,
|
|
85
|
-
content: [{ type: "text", text:
|
|
109
|
+
content: [{ type: "text", text: `[ERROR] Execution failed: ${message}` }],
|
|
86
110
|
};
|
|
87
111
|
}
|
|
88
112
|
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Storage } from "../../../src/shared/storage.js";
|
|
2
|
+
/**
|
|
3
|
+
* [DATA] MCP Resource Definitions
|
|
4
|
+
*/
|
|
5
|
+
export const RESOURCES = [
|
|
6
|
+
{
|
|
7
|
+
uri: "atabey://army/status",
|
|
8
|
+
name: "Agent Army Status",
|
|
9
|
+
description: "Real-time state and active tasks of all specialized agents.",
|
|
10
|
+
mimeType: "text/markdown"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
uri: "atabey://plan/active",
|
|
14
|
+
name: "Active Execution Plan",
|
|
15
|
+
description: "The current DAG of tasks and their completion status.",
|
|
16
|
+
mimeType: "text/markdown"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
uri: "atabey://memory/project",
|
|
20
|
+
name: "Project Memory",
|
|
21
|
+
description: "The central source of truth for project context (PROJECT_MEMORY.md).",
|
|
22
|
+
mimeType: "text/markdown"
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
export async function handleReadResource(uri) {
|
|
26
|
+
if (uri === "atabey://army/status") {
|
|
27
|
+
const agents = Storage.getAllAgents();
|
|
28
|
+
let md = "# [AI] Agent Army Status\n\n| Agent | State | Active Task | Last Updated |\n| :--- | :--- | :--- | :--- |\n";
|
|
29
|
+
agents.forEach((a) => {
|
|
30
|
+
md += `| @${a.name} | ${a.state} | ${a.task} | ${a.last_updated} |\n`;
|
|
31
|
+
});
|
|
32
|
+
return md;
|
|
33
|
+
}
|
|
34
|
+
if (uri === "atabey://plan/active") {
|
|
35
|
+
const tasks = Storage.getTasks();
|
|
36
|
+
let md = "# 📋 Active Execution Plan\n\n| ID | Task | Agent | Status | Dependencies |\n| :--- | :--- | :--- | :--- | :--- |\n";
|
|
37
|
+
tasks.forEach((t) => {
|
|
38
|
+
const deps = t.dependencies.join(", ") || "-";
|
|
39
|
+
md += `| ${t.id} | ${t.description} | ${t.agent} | ${t.status} | ${deps} |\n`;
|
|
40
|
+
});
|
|
41
|
+
return md;
|
|
42
|
+
}
|
|
43
|
+
if (uri === "atabey://memory/project") {
|
|
44
|
+
const fs = await import("fs");
|
|
45
|
+
const path = await import("path");
|
|
46
|
+
const { getFrameworkDir } = await import("../../../src/cli/utils/memory.js");
|
|
47
|
+
const projectRoot = process.env.ATABEY_PROJECT_ROOT || process.cwd();
|
|
48
|
+
const fwDir = getFrameworkDir();
|
|
49
|
+
const p = path.isAbsolute(fwDir)
|
|
50
|
+
? path.join(fwDir, "memory", "PROJECT_MEMORY.md")
|
|
51
|
+
: path.join(projectRoot, fwDir, "memory", "PROJECT_MEMORY.md");
|
|
52
|
+
if (fs.existsSync(p)) {
|
|
53
|
+
return fs.readFileSync(p, "utf8");
|
|
54
|
+
}
|
|
55
|
+
return "Project memory not found. Run 'atabey init' first.";
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
58
|
+
}
|
|
@@ -38,7 +38,7 @@ export async function handleAcquireLock(projectRoot, args) {
|
|
|
38
38
|
const lockData = JSON.stringify({ agent, timestamp: new Date().toISOString() });
|
|
39
39
|
fs.writeFileSync(lockPath, lockData, { flag: "wx" });
|
|
40
40
|
return {
|
|
41
|
-
content: [{ type: "text", text:
|
|
41
|
+
content: [{ type: "text", text: `[OK] Lock acquired for resource '${resource}' by ${agent}.` }]
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
catch (e) {
|
|
@@ -70,11 +70,11 @@ export async function handleReleaseLock(projectRoot, args) {
|
|
|
70
70
|
if (lockData.agent !== agent) {
|
|
71
71
|
return {
|
|
72
72
|
isError: true,
|
|
73
|
-
content: [{ type: "text", text:
|
|
73
|
+
content: [{ type: "text", text: `[ERROR] Denied: You do not own the lock for '${resource}'. Owned by ${lockData.agent}.` }]
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
fs.unlinkSync(lockPath);
|
|
77
|
-
return { content: [{ type: "text", text:
|
|
77
|
+
return { content: [{ type: "text", text: `[OK] Lock released for resource '${resource}' by ${agent}.` }] };
|
|
78
78
|
}
|
|
79
79
|
catch (e) {
|
|
80
80
|
return { isError: true, content: [{ type: "text", text: `Failed to release lock: ${String(e)}` }] };
|
|
@@ -6,7 +6,7 @@ import { resolveFrameworkDir } from "../../utils/security.js";
|
|
|
6
6
|
* This can be used to validate permissions and active status.
|
|
7
7
|
*/
|
|
8
8
|
export async function handleRegisterAgent(projectRoot, args) {
|
|
9
|
-
const { agent, role, capability = 5 } = args;
|
|
9
|
+
const { agent, role, capability = 5, specialties } = args;
|
|
10
10
|
const frameworkDir = resolveFrameworkDir(projectRoot);
|
|
11
11
|
const registryDir = path.join(projectRoot, frameworkDir, "registry");
|
|
12
12
|
const agentFile = path.join(registryDir, `${agent.replace("@", "")}_active.json`);
|
|
@@ -17,12 +17,13 @@ export async function handleRegisterAgent(projectRoot, args) {
|
|
|
17
17
|
agent,
|
|
18
18
|
role,
|
|
19
19
|
capability,
|
|
20
|
+
specialties,
|
|
20
21
|
last_seen: new Date().toISOString(),
|
|
21
22
|
status: "ACTIVE"
|
|
22
23
|
};
|
|
23
24
|
fs.writeFileSync(agentFile, JSON.stringify(agentData, null, 2));
|
|
24
25
|
return {
|
|
25
|
-
content: [{ type: "text", text:
|
|
26
|
+
content: [{ type: "text", text: `[ATABEY] Agent ${agent} (${role}) registered successfully in the Atabey Control Plane.` }]
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
catch (e) {
|
|
@@ -232,7 +232,12 @@ export const TOOLS = [
|
|
|
232
232
|
properties: {
|
|
233
233
|
agent: { type: "string", description: "The agent name (e.g., '@backend')." },
|
|
234
234
|
role: { type: "string", description: "The role of the agent." },
|
|
235
|
-
capability: { type: "number", description: "The capability score (1-10)." }
|
|
235
|
+
capability: { type: "number", description: "The capability score (1-10)." },
|
|
236
|
+
specialties: {
|
|
237
|
+
type: "object",
|
|
238
|
+
additionalProperties: { type: "number" },
|
|
239
|
+
description: "Sub-specialty weights mapping (e.g. {\"postgres\": 10, \"redis\": 8})"
|
|
240
|
+
}
|
|
236
241
|
},
|
|
237
242
|
required: ["agent", "role"]
|
|
238
243
|
}
|
|
@@ -274,6 +279,33 @@ export const TOOLS = [
|
|
|
274
279
|
description: "Run the project's linter (e.g., ESLint) to check for code quality and style issues.",
|
|
275
280
|
inputSchema: { type: "object", properties: {} },
|
|
276
281
|
},
|
|
282
|
+
{
|
|
283
|
+
name: "submit_plan",
|
|
284
|
+
description: "Submit a structured DAG plan of tasks for the project. This will be decomposed and queued for execution.",
|
|
285
|
+
inputSchema: {
|
|
286
|
+
type: "object",
|
|
287
|
+
properties: {
|
|
288
|
+
tasks: {
|
|
289
|
+
type: "array",
|
|
290
|
+
items: {
|
|
291
|
+
type: "object",
|
|
292
|
+
properties: {
|
|
293
|
+
id: { type: "string", description: "Unique task ID (e.g. TASK_01)" },
|
|
294
|
+
agent: { type: "string", description: "The agent responsible for the task (e.g. @backend)" },
|
|
295
|
+
task: { type: "string", description: "The task description" },
|
|
296
|
+
dependencies: {
|
|
297
|
+
type: "array",
|
|
298
|
+
items: { type: "string" },
|
|
299
|
+
description: "List of task IDs that must be completed before this task."
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
required: ["id", "agent", "task"]
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
required: ["tasks"],
|
|
307
|
+
},
|
|
308
|
+
},
|
|
277
309
|
{
|
|
278
310
|
name: "view_file",
|
|
279
311
|
description: "Alias for read_file. Reads the content of a file within the project.",
|
|
@@ -2,11 +2,12 @@ import fs from "fs";
|
|
|
2
2
|
import { safePath } from "../../utils/security.js";
|
|
3
3
|
import { writeTextFileAtomic } from "../../utils/fs.js";
|
|
4
4
|
import { Metrics } from "../../utils/metrics.js";
|
|
5
|
-
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
5
|
+
import { verifyCorporateCompliance, verifyRiskAndAwaitApproval } from "../../utils/compliance.js";
|
|
6
|
+
import { verifyWritePermission } from "../../utils/permissions.js";
|
|
6
7
|
/**
|
|
7
8
|
* Performs multiple surgical text replacements across multiple files in a single batch.
|
|
8
9
|
*/
|
|
9
|
-
export function handleBatchSurgicalEdit(projectRoot, args) {
|
|
10
|
+
export async function handleBatchSurgicalEdit(projectRoot, args) {
|
|
10
11
|
const edits = args.edits;
|
|
11
12
|
if (!Array.isArray(edits) || edits.length === 0) {
|
|
12
13
|
const err = "No edits provided in the batch request.";
|
|
@@ -17,6 +18,8 @@ export function handleBatchSurgicalEdit(projectRoot, args) {
|
|
|
17
18
|
let totalTokens = 0;
|
|
18
19
|
for (const edit of edits) {
|
|
19
20
|
const filePath = safePath(projectRoot, edit.path);
|
|
21
|
+
// ENFORCE PERMISSION MATRIX
|
|
22
|
+
verifyWritePermission(projectRoot, edit.path);
|
|
20
23
|
if (!fs.existsSync(filePath)) {
|
|
21
24
|
const err = `File not found: ${edit.path}`;
|
|
22
25
|
Metrics.logError(projectRoot, "@mcp", `batch_surgical_edit:${edit.path}`, err);
|
|
@@ -44,10 +47,12 @@ export function handleBatchSurgicalEdit(projectRoot, args) {
|
|
|
44
47
|
: content.replace(oldText, newText);
|
|
45
48
|
// ENFORCE CORPORATE COMPLIANCE
|
|
46
49
|
verifyCorporateCompliance(newContent, edit.path);
|
|
50
|
+
// ENFORCE RISK & HUMAN APPROVAL GATEWAY
|
|
51
|
+
await verifyRiskAndAwaitApproval(projectRoot, newContent, edit.path);
|
|
47
52
|
writeTextFileAtomic(filePath, newContent);
|
|
48
53
|
const tokens = Metrics.estimateTokens(newText);
|
|
49
54
|
totalTokens += tokens;
|
|
50
|
-
results.push(
|
|
55
|
+
results.push(`[OK] Edited ${edit.path}`);
|
|
51
56
|
}
|
|
52
57
|
Metrics.logUsage(projectRoot, "@mcp", `batch_surgical_edit: ${edits.length} files`, totalTokens);
|
|
53
58
|
return {
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import { safePath } from "../../utils/security.js";
|
|
3
3
|
import { Metrics } from "../../utils/metrics.js";
|
|
4
|
-
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
5
|
-
|
|
4
|
+
import { verifyCorporateCompliance, verifyRiskAndAwaitApproval } from "../../utils/compliance.js";
|
|
5
|
+
import { verifyWritePermission } from "../../utils/permissions.js";
|
|
6
|
+
export async function handlePatchFile(projectRoot, args) {
|
|
6
7
|
const filePath = safePath(projectRoot, args.path);
|
|
8
|
+
// ENFORCE PERMISSION MATRIX
|
|
9
|
+
verifyWritePermission(projectRoot, args.path);
|
|
7
10
|
const lines = fs.readFileSync(filePath, "utf8").split("\n");
|
|
8
11
|
const start = args.startLine - 1;
|
|
9
12
|
const end = args.endLine;
|
|
@@ -22,8 +25,10 @@ export function handlePatchFile(projectRoot, args) {
|
|
|
22
25
|
const patchedContent = lines.join("\n");
|
|
23
26
|
// ENFORCE CORPORATE COMPLIANCE
|
|
24
27
|
verifyCorporateCompliance(patchedContent, args.path);
|
|
28
|
+
// ENFORCE RISK & HUMAN APPROVAL GATEWAY
|
|
29
|
+
await verifyRiskAndAwaitApproval(projectRoot, patchedContent, args.path);
|
|
25
30
|
fs.writeFileSync(filePath, patchedContent);
|
|
26
31
|
const tokens = Metrics.estimateTokens(args.newContent);
|
|
27
32
|
Metrics.logUsage(projectRoot, "@mcp", `patch_file: ${args.path}`, tokens);
|
|
28
|
-
return { content: [{ type: "text", text:
|
|
33
|
+
return { content: [{ type: "text", text: `[OK] File patched successfully: ${args.path}` }] };
|
|
29
34
|
}
|
|
@@ -5,14 +5,14 @@ export function handleReadFile(projectRoot, args) {
|
|
|
5
5
|
if (!args.path) {
|
|
6
6
|
const err = "Missing 'path' argument.";
|
|
7
7
|
Metrics.logError(projectRoot, "@mcp", "read_file", err);
|
|
8
|
-
return { isError: true, content: [{ type: "text", text:
|
|
8
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
9
9
|
}
|
|
10
10
|
try {
|
|
11
11
|
const filePath = safePath(projectRoot, args.path);
|
|
12
12
|
if (!fs.existsSync(filePath)) {
|
|
13
13
|
const err = `File not found: ${args.path}`;
|
|
14
14
|
Metrics.logError(projectRoot, "@mcp", "read_file", err);
|
|
15
|
-
return { isError: true, content: [{ type: "text", text:
|
|
15
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
16
16
|
}
|
|
17
17
|
const startLine = args.startLine;
|
|
18
18
|
const endLine = args.endLine;
|
|
@@ -46,6 +46,6 @@ export function handleReadFile(projectRoot, args) {
|
|
|
46
46
|
catch (e) {
|
|
47
47
|
const err = `Failed to read file: ${String(e)}`;
|
|
48
48
|
Metrics.logError(projectRoot, "@mcp", `read_file:${args.path}`, err);
|
|
49
|
-
return { isError: true, content: [{ type: "text", text:
|
|
49
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -2,9 +2,12 @@ import fs from "fs";
|
|
|
2
2
|
import { safePath } from "../../utils/security.js";
|
|
3
3
|
import { writeTextFileAtomic } from "../../utils/fs.js";
|
|
4
4
|
import { Metrics } from "../../utils/metrics.js";
|
|
5
|
-
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
6
|
-
|
|
5
|
+
import { verifyCorporateCompliance, verifyRiskAndAwaitApproval } from "../../utils/compliance.js";
|
|
6
|
+
import { verifyWritePermission } from "../../utils/permissions.js";
|
|
7
|
+
export async function handleReplaceText(projectRoot, args) {
|
|
7
8
|
const filePath = safePath(projectRoot, args.path);
|
|
9
|
+
// ENFORCE PERMISSION MATRIX
|
|
10
|
+
verifyWritePermission(projectRoot, args.path);
|
|
8
11
|
const content = fs.readFileSync(filePath, "utf8");
|
|
9
12
|
const oldText = args.oldText;
|
|
10
13
|
const newText = args.newText;
|
|
@@ -38,8 +41,10 @@ export function handleReplaceText(projectRoot, args) {
|
|
|
38
41
|
}
|
|
39
42
|
// ENFORCE CORPORATE COMPLIANCE
|
|
40
43
|
verifyCorporateCompliance(newContent, args.path);
|
|
44
|
+
// ENFORCE RISK & HUMAN APPROVAL GATEWAY
|
|
45
|
+
await verifyRiskAndAwaitApproval(projectRoot, newContent, args.path);
|
|
41
46
|
writeTextFileAtomic(filePath, newContent);
|
|
42
47
|
const tokens = Metrics.estimateTokens(newText);
|
|
43
48
|
Metrics.logUsage(projectRoot, "@mcp", `replace_text: ${args.path}`, tokens);
|
|
44
|
-
return { content: [{ type: "text", text:
|
|
49
|
+
return { content: [{ type: "text", text: `[OK] Surgical edit successful in ${args.path}` }] };
|
|
45
50
|
}
|
|
@@ -3,18 +3,23 @@ import path from "path";
|
|
|
3
3
|
import { safePath, resolveFrameworkDir } from "../../utils/security.js";
|
|
4
4
|
import { writeTextFileAtomic, appendFileSafe } from "../../utils/fs.js";
|
|
5
5
|
import { Metrics } from "../../utils/metrics.js";
|
|
6
|
-
import { verifyCorporateCompliance } from "../../utils/compliance.js";
|
|
7
|
-
|
|
6
|
+
import { verifyCorporateCompliance, verifyRiskAndAwaitApproval } from "../../utils/compliance.js";
|
|
7
|
+
import { verifyWritePermission } from "../../utils/permissions.js";
|
|
8
|
+
export async function handleWriteFile(projectRoot, args) {
|
|
8
9
|
if (!args.path || args.content === undefined) {
|
|
9
10
|
const err = "Missing 'path' or 'content' argument.";
|
|
10
11
|
Metrics.logError(projectRoot, "@mcp", "write_file", err);
|
|
11
|
-
return { isError: true, content: [{ type: "text", text:
|
|
12
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
12
13
|
}
|
|
13
14
|
try {
|
|
14
15
|
const filePath = safePath(projectRoot, args.path);
|
|
15
16
|
const content = args.content;
|
|
17
|
+
// ENFORCE PERMISSION MATRIX
|
|
18
|
+
verifyWritePermission(projectRoot, args.path);
|
|
16
19
|
// ENFORCE CORPORATE COMPLIANCE
|
|
17
20
|
verifyCorporateCompliance(content, args.path);
|
|
21
|
+
// ENFORCE RISK & HUMAN APPROVAL GATEWAY
|
|
22
|
+
await verifyRiskAndAwaitApproval(projectRoot, content, args.path);
|
|
18
23
|
writeTextFileAtomic(filePath, content);
|
|
19
24
|
// AUTO-LOGGING & METRICS
|
|
20
25
|
const tokens = Metrics.estimateTokens(content);
|
|
@@ -28,11 +33,11 @@ export function handleWriteFile(projectRoot, args) {
|
|
|
28
33
|
}
|
|
29
34
|
}
|
|
30
35
|
catch { /* ignore memory logging errors */ }
|
|
31
|
-
return { content: [{ type: "text", text:
|
|
36
|
+
return { content: [{ type: "text", text: `[OK] File written: ${args.path}` }] };
|
|
32
37
|
}
|
|
33
38
|
catch (e) {
|
|
34
39
|
const err = `Failed to write file: ${String(e)}`;
|
|
35
40
|
Metrics.logError(projectRoot, "@mcp", `write_file:${args.path}`, err);
|
|
36
|
-
return { isError: true, content: [{ type: "text", text:
|
|
41
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -22,7 +22,7 @@ export function handleAuditDependencies(projectRoot, _args) {
|
|
|
22
22
|
for (const [group, patterns] of Object.entries(similarityGroups)) {
|
|
23
23
|
const found = depNames.filter(d => patterns.some(p => d.includes(p)));
|
|
24
24
|
if (found.length > 1) {
|
|
25
|
-
results.push(
|
|
25
|
+
results.push(`[WARN] Potential redundancy in [${group}]: Found ${found.join(", ")}`);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
// 2. Scan for "any" usage in package names (bad practice markers)
|
|
@@ -35,7 +35,7 @@ export function handleAuditDependencies(projectRoot, _args) {
|
|
|
35
35
|
type: "text",
|
|
36
36
|
text: results.length > 0
|
|
37
37
|
? `Dependency Audit Results:\n\n${results.join("\n")}`
|
|
38
|
-
: "
|
|
38
|
+
: "[OK] Dependencies look clean and consolidated."
|
|
39
39
|
}]
|
|
40
40
|
};
|
|
41
41
|
}
|
|
@@ -9,7 +9,7 @@ export function handleRunTests(projectRoot, args) {
|
|
|
9
9
|
try {
|
|
10
10
|
const output = execSync(testCommand, { cwd: projectRoot, encoding: "utf8", stdio: "pipe" });
|
|
11
11
|
return {
|
|
12
|
-
content: [{ type: "text", text:
|
|
12
|
+
content: [{ type: "text", text: `[OK] Tests passed successfully for ${language}!\n\n${output}` }]
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
catch (error) {
|
|
@@ -20,7 +20,7 @@ export function handleRunTests(projectRoot, args) {
|
|
|
20
20
|
isError: true,
|
|
21
21
|
content: [{
|
|
22
22
|
type: "text",
|
|
23
|
-
text:
|
|
23
|
+
text: `[ERROR] Tests FAILED for ${language}!\n\n--- STDOUT ---\n${stdout}\n\n--- STDERR ---\n${stderr}`
|
|
24
24
|
}]
|
|
25
25
|
};
|
|
26
26
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { safeExec } from "../../utils/cli.js";
|
|
2
|
+
export function handleSubmitPlan(projectRoot, args) {
|
|
3
|
+
if (!args.tasks || !Array.isArray(args.tasks)) {
|
|
4
|
+
return {
|
|
5
|
+
isError: true,
|
|
6
|
+
content: [{ type: "text", text: "[ERROR] Error: 'tasks' array is required for submit_plan." }]
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
const planJson = JSON.stringify(args.tasks);
|
|
10
|
+
// Escape for shell if necessary, but safeExec handles arguments as an array
|
|
11
|
+
const output = safeExec("npx", ["atabey", "plan:submit", planJson], projectRoot);
|
|
12
|
+
return { content: [{ type: "text", text: output }] };
|
|
13
|
+
}
|
|
@@ -4,5 +4,5 @@ export function handleUpdateProjectMemory(projectRoot, args) {
|
|
|
4
4
|
const content = args.content;
|
|
5
5
|
// Using execFileSync with array args prevents command injection
|
|
6
6
|
safeExec("npx", ["atabey", "update_project_memory", section, content], projectRoot);
|
|
7
|
-
return { content: [{ type: "text", text:
|
|
7
|
+
return { content: [{ type: "text", text: `[OK] Section ${section} updated.` }] };
|
|
8
8
|
}
|
|
@@ -15,6 +15,7 @@ import { handleRunTests } from "./framework/run_tests.js";
|
|
|
15
15
|
import { handleGetSystemHealth } from "./observability/get_health.js";
|
|
16
16
|
import { handleCheckPorts } from "./observability/check_ports.js";
|
|
17
17
|
import { handleOrchestrateLoop } from "./framework/orchestrate.js";
|
|
18
|
+
import { handleSubmitPlan } from "./framework/submit_plan.js";
|
|
18
19
|
import { handleUpdateContractHash } from "./framework/update_contract_hash.js";
|
|
19
20
|
import { handleReadProjectMemory } from "./memory/read_memory.js";
|
|
20
21
|
import { handleGetMemoryInsights } from "./memory/get_insights.js";
|
|
@@ -48,6 +49,7 @@ export const toolHandlers = {
|
|
|
48
49
|
get_system_health: bind(handleGetSystemHealth),
|
|
49
50
|
check_active_ports: bind(handleCheckPorts),
|
|
50
51
|
orchestrate_loop: bind(handleOrchestrateLoop),
|
|
52
|
+
submit_plan: bind(handleSubmitPlan),
|
|
51
53
|
send_agent_message: bind(handleSendAgentMessage),
|
|
52
54
|
log_agent_action: bind(handleLogAgentAction),
|
|
53
55
|
update_contract_hash: bind(handleUpdateContractHash),
|
|
@@ -25,7 +25,7 @@ export function handleGetMemoryInsights(projectRoot, _args) {
|
|
|
25
25
|
.slice(-5)
|
|
26
26
|
.join("\n");
|
|
27
27
|
}
|
|
28
|
-
const insights =
|
|
28
|
+
const insights = `[MEMORY] **Memory Insights**\n- **Phase:** ${activePhase}\n- **Trace:** ${activeTrace}\n\n**Recent Actions:**\n${recentHistory}`;
|
|
29
29
|
return { content: [{ type: "text", text: insights }] };
|
|
30
30
|
}
|
|
31
31
|
catch (e) {
|
|
@@ -18,5 +18,5 @@ export function handleLogAgentAction(projectRoot, args) {
|
|
|
18
18
|
};
|
|
19
19
|
fs.mkdirSync(path.dirname(logPath), { recursive: true });
|
|
20
20
|
fs.appendFileSync(logPath, JSON.stringify(logEntry) + "\n");
|
|
21
|
-
return { content: [{ type: "text", text:
|
|
21
|
+
return { content: [{ type: "text", text: `[OK] Action logged for ${agent} to ${path.join(frameworkDir, "logs", `${agentName}.json`)}` }] };
|
|
22
22
|
}
|
|
@@ -8,7 +8,7 @@ export async function handleSendAgentMessage(projectRoot, args) {
|
|
|
8
8
|
if (!to || !category || !content || !traceId) {
|
|
9
9
|
const err = "Missing required messaging arguments (to, category, content, or traceId).";
|
|
10
10
|
Metrics.logError(projectRoot, from, "send_agent_message", err);
|
|
11
|
-
return { isError: true, content: [{ type: "text", text:
|
|
11
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
12
12
|
}
|
|
13
13
|
const frameworkDir = resolveFrameworkDir(projectRoot);
|
|
14
14
|
const messagesDir = path.join(projectRoot, frameworkDir, "messages");
|
|
@@ -47,14 +47,14 @@ export async function handleSendAgentMessage(projectRoot, args) {
|
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
else {
|
|
50
|
-
return { content: [{ type: "text", text:
|
|
50
|
+
return { content: [{ type: "text", text: `[ERROR] Unexpected lock acquisition error: ${error.message || String(err)}` }], isError: true };
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
if (!acquired) {
|
|
55
55
|
const err = `Could not send message to ${to}: Hermes lock is busy.`;
|
|
56
56
|
Metrics.logError(projectRoot, from, "send_agent_message", err);
|
|
57
|
-
return { content: [{ type: "text", text:
|
|
57
|
+
return { content: [{ type: "text", text: `[ERROR] ${err}` }], isError: true };
|
|
58
58
|
}
|
|
59
59
|
try {
|
|
60
60
|
const defaultPriority = (category === "ALERT" || category === "ACTION") ? "HIGH" : "NORMAL";
|
|
@@ -74,12 +74,12 @@ export async function handleSendAgentMessage(projectRoot, args) {
|
|
|
74
74
|
requiresApproval: finalRequiresApproval
|
|
75
75
|
};
|
|
76
76
|
fs.appendFileSync(messagePath, JSON.stringify(message) + "\n");
|
|
77
|
-
return { content: [{ type: "text", text:
|
|
77
|
+
return { content: [{ type: "text", text: `[OK] Message sent to ${to} (from: ${from})` }] };
|
|
78
78
|
}
|
|
79
79
|
catch (e) {
|
|
80
80
|
const err = `Failed to write message: ${String(e)}`;
|
|
81
81
|
Metrics.logError(projectRoot, from, "send_agent_message", err);
|
|
82
|
-
return { isError: true, content: [{ type: "text", text:
|
|
82
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
83
83
|
}
|
|
84
84
|
finally {
|
|
85
85
|
if (acquired && fs.existsSync(lockPath)) {
|
|
@@ -14,7 +14,7 @@ export function handleCheckPorts(projectRoot, args) {
|
|
|
14
14
|
return {
|
|
15
15
|
content: [{
|
|
16
16
|
type: "text",
|
|
17
|
-
text:
|
|
17
|
+
text: `[SIGNAL] **Active Listening Ports:**\n\n${output || "No active listening ports found matching filter."}`
|
|
18
18
|
}]
|
|
19
19
|
};
|
|
20
20
|
}
|
|
@@ -17,13 +17,13 @@ export function handleCheckLint(projectRoot, _args) {
|
|
|
17
17
|
Metrics.logError(projectRoot, "@mcp", "check_lint", err);
|
|
18
18
|
resolve({
|
|
19
19
|
isError: true,
|
|
20
|
-
content: [{ type: "text", text:
|
|
20
|
+
content: [{ type: "text", text: `[ERROR] Lint Errors Found (${language}):\n\n${output}` }]
|
|
21
21
|
});
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
24
|
Metrics.logUsage(projectRoot, "@mcp", "check_lint", tokens);
|
|
25
25
|
resolve({
|
|
26
|
-
content: [{ type: "text", text:
|
|
26
|
+
content: [{ type: "text", text: `[OK] Lint check passed successfully for ${language}:\n\n${output}` }]
|
|
27
27
|
});
|
|
28
28
|
});
|
|
29
29
|
});
|
|
@@ -42,7 +42,7 @@ export function handleGetProjectGaps(projectRoot, args) {
|
|
|
42
42
|
type: "text",
|
|
43
43
|
text: results.length > 0
|
|
44
44
|
? `Found ${results.length} gaps/todos:\n\n${results.join("\n")}`
|
|
45
|
-
: "
|
|
45
|
+
: "[OK] No major gaps or TODOs found in the scanned directory."
|
|
46
46
|
}]
|
|
47
47
|
};
|
|
48
48
|
}
|
|
@@ -11,7 +11,7 @@ export function handleGrepSearch(projectRoot, args) {
|
|
|
11
11
|
if (!pattern) {
|
|
12
12
|
const err = "Search pattern is required.";
|
|
13
13
|
Metrics.logError(projectRoot, "@mcp", "grep_search", err);
|
|
14
|
-
return { isError: true, content: [{ type: "text", text:
|
|
14
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
15
15
|
}
|
|
16
16
|
const results = [];
|
|
17
17
|
try {
|
|
@@ -20,7 +20,7 @@ export function handleGrepSearch(projectRoot, args) {
|
|
|
20
20
|
catch (e) {
|
|
21
21
|
const err = `Invalid regex pattern: ${String(e)}`;
|
|
22
22
|
Metrics.logError(projectRoot, "@mcp", "grep_search", err);
|
|
23
|
-
return { isError: true, content: [{ type: "text", text:
|
|
23
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
24
24
|
}
|
|
25
25
|
const walk = (dir) => {
|
|
26
26
|
if (results.length > 100)
|
|
@@ -62,7 +62,7 @@ export function handleGrepSearch(projectRoot, args) {
|
|
|
62
62
|
catch (e) {
|
|
63
63
|
const err = `Search failed: ${String(e)}`;
|
|
64
64
|
Metrics.logError(projectRoot, "@mcp", "grep_search", err);
|
|
65
|
-
return { isError: true, content: [{ type: "text", text:
|
|
65
|
+
return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
|
|
66
66
|
}
|
|
67
67
|
return {
|
|
68
68
|
content: [{
|