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.
Files changed (144) hide show
  1. package/dist/{constants.js → framework-mcp/src/constants.js} +1 -1
  2. package/dist/{index.js → framework-mcp/src/index.js} +29 -5
  3. package/dist/framework-mcp/src/resources/index.js +58 -0
  4. package/dist/{tools → framework-mcp/src/tools}/control_plane/locking.js +3 -3
  5. package/dist/{tools → framework-mcp/src/tools}/control_plane/registry.js +3 -2
  6. package/dist/{tools → framework-mcp/src/tools}/definitions.js +33 -1
  7. package/dist/{tools → framework-mcp/src/tools}/file_system/batch_surgical_edit.js +8 -3
  8. package/dist/{tools → framework-mcp/src/tools}/file_system/patch_file.js +8 -3
  9. package/dist/{tools → framework-mcp/src/tools}/file_system/read_file.js +3 -3
  10. package/dist/{tools → framework-mcp/src/tools}/file_system/replace_text.js +8 -3
  11. package/dist/{tools → framework-mcp/src/tools}/file_system/write_file.js +10 -5
  12. package/dist/{tools → framework-mcp/src/tools}/framework/audit_deps.js +2 -2
  13. package/dist/{tools → framework-mcp/src/tools}/framework/run_tests.js +2 -2
  14. package/dist/framework-mcp/src/tools/framework/submit_plan.js +13 -0
  15. package/dist/{tools → framework-mcp/src/tools}/framework/update_memory.js +1 -1
  16. package/dist/{tools → framework-mcp/src/tools}/index.js +2 -0
  17. package/dist/{tools → framework-mcp/src/tools}/memory/get_insights.js +1 -1
  18. package/dist/{tools → framework-mcp/src/tools}/messaging/log_action.js +1 -1
  19. package/dist/{tools → framework-mcp/src/tools}/messaging/send_message.js +5 -5
  20. package/dist/{tools → framework-mcp/src/tools}/observability/check_ports.js +1 -1
  21. package/dist/{tools → framework-mcp/src/tools}/quality/check_lint.js +2 -2
  22. package/dist/{tools → framework-mcp/src/tools}/search/get_gaps.js +1 -1
  23. package/dist/{tools → framework-mcp/src/tools}/search/grep_search.js +3 -3
  24. package/dist/framework-mcp/src/utils/compliance.js +231 -0
  25. package/dist/framework-mcp/src/utils/permissions.js +71 -0
  26. package/dist/src/cli/adapters/core.js +78 -0
  27. package/dist/src/cli/adapters/index.js +5 -0
  28. package/dist/src/cli/adapters/paths.js +101 -0
  29. package/dist/src/cli/adapters/scaffold.js +71 -0
  30. package/dist/src/cli/adapters/utils.js +75 -0
  31. package/dist/src/cli/commands/approve.js +63 -0
  32. package/dist/src/cli/commands/check.js +181 -0
  33. package/dist/src/cli/commands/compliance.js +50 -0
  34. package/dist/src/cli/commands/contract.js +50 -0
  35. package/dist/src/cli/commands/dashboard.js +123 -0
  36. package/dist/src/cli/commands/explorer.js +42 -0
  37. package/dist/src/cli/commands/git.js +40 -0
  38. package/dist/src/cli/commands/init/create-agent.js +58 -0
  39. package/dist/src/cli/commands/init/scaffold-core.js +112 -0
  40. package/dist/src/cli/commands/init/scaffold-docs.js +34 -0
  41. package/dist/src/cli/commands/init/scaffold-ops.js +80 -0
  42. package/dist/src/cli/commands/init/scaffold-standards.js +67 -0
  43. package/dist/src/cli/commands/init.js +167 -0
  44. package/dist/src/cli/commands/knowledge.js +42 -0
  45. package/dist/src/cli/commands/lint.js +22 -0
  46. package/dist/src/cli/commands/log.js +10 -0
  47. package/dist/src/cli/commands/memory.js +4 -0
  48. package/dist/src/cli/commands/orchestrate.js +159 -0
  49. package/dist/src/cli/commands/plan.js +117 -0
  50. package/dist/src/cli/commands/script.js +19 -0
  51. package/dist/src/cli/commands/security.js +36 -0
  52. package/dist/src/cli/commands/status.js +97 -0
  53. package/dist/src/cli/commands/trace.js +109 -0
  54. package/dist/src/cli/index.js +338 -0
  55. package/dist/src/cli/shims.js +66 -0
  56. package/dist/src/cli/utils/claude.js +56 -0
  57. package/dist/src/cli/utils/compliance.js +173 -0
  58. package/dist/src/cli/utils/config-schema.js +42 -0
  59. package/dist/src/cli/utils/fs.js +137 -0
  60. package/dist/src/cli/utils/i18n.js +30 -0
  61. package/dist/src/cli/utils/memory.js +276 -0
  62. package/dist/src/cli/utils/pkg.js +282 -0
  63. package/dist/src/cli/utils/schemas.js +19 -0
  64. package/dist/src/cli/utils/string.js +49 -0
  65. package/dist/src/cli/utils/time.js +27 -0
  66. package/dist/src/cli/utils/ui.js +58 -0
  67. package/dist/src/contracts/index.js +1 -0
  68. package/dist/src/contracts/tasks.js +20 -0
  69. package/dist/src/dashboard/vite.config.js +15 -0
  70. package/dist/src/modules/adapters/definitions.js +140 -0
  71. package/dist/src/modules/adapters/registry.js +18 -0
  72. package/dist/src/modules/adapters/shared.js +104 -0
  73. package/dist/src/modules/adapters/types.js +1 -0
  74. package/dist/src/modules/agents/definitions.js +457 -0
  75. package/dist/src/modules/agents/registry/analyst.js +39 -0
  76. package/dist/src/modules/agents/registry/architect.js +42 -0
  77. package/dist/src/modules/agents/registry/backend.js +49 -0
  78. package/dist/src/modules/agents/registry/database.js +45 -0
  79. package/dist/src/modules/agents/registry/devops.js +45 -0
  80. package/dist/src/modules/agents/registry/explorer.js +36 -0
  81. package/dist/src/modules/agents/registry/frontend.js +51 -0
  82. package/dist/src/modules/agents/registry/git.js +36 -0
  83. package/dist/src/modules/agents/registry/manager.js +53 -0
  84. package/dist/src/modules/agents/registry/mobile.js +39 -0
  85. package/dist/src/modules/agents/registry/native.js +39 -0
  86. package/dist/src/modules/agents/registry/quality.js +41 -0
  87. package/dist/src/modules/agents/registry/security.js +43 -0
  88. package/dist/src/modules/agents/types.js +1 -0
  89. package/dist/src/modules/engines/evaluation-engine.js +102 -0
  90. package/dist/src/modules/engines/health-engine.js +49 -0
  91. package/dist/src/modules/engines/planning-engine.js +78 -0
  92. package/dist/src/modules/engines/risk-engine.js +105 -0
  93. package/dist/src/modules/engines/routing-engine.js +73 -0
  94. package/dist/src/modules/engines/types.js +1 -0
  95. package/dist/src/modules/skills/definitions.js +70 -0
  96. package/dist/src/shared/constants.js +186 -0
  97. package/dist/src/shared/errors.js +68 -0
  98. package/dist/src/shared/fs.js +51 -0
  99. package/dist/src/shared/logger.js +116 -0
  100. package/dist/src/shared/storage.js +207 -0
  101. package/dist/src/shared/types.js +12 -0
  102. package/package.json +1 -1
  103. package/src/constants.ts +1 -1
  104. package/src/declarations.d.ts +3 -1
  105. package/src/index.ts +31 -4
  106. package/src/resources/index.ts +65 -0
  107. package/src/tools/control_plane/locking.ts +3 -3
  108. package/src/tools/control_plane/registry.ts +3 -2
  109. package/src/tools/definitions.ts +33 -1
  110. package/src/tools/file_system/batch_surgical_edit.ts +11 -3
  111. package/src/tools/file_system/patch_file.ts +10 -3
  112. package/src/tools/file_system/read_file.ts +3 -3
  113. package/src/tools/file_system/replace_text.ts +10 -3
  114. package/src/tools/file_system/write_file.ts +12 -5
  115. package/src/tools/framework/audit_deps.ts +2 -2
  116. package/src/tools/framework/run_tests.ts +2 -2
  117. package/src/tools/framework/submit_plan.ts +26 -0
  118. package/src/tools/framework/update_memory.ts +1 -1
  119. package/src/tools/index.ts +2 -0
  120. package/src/tools/memory/get_insights.ts +1 -1
  121. package/src/tools/messaging/log_action.ts +1 -1
  122. package/src/tools/messaging/send_message.ts +5 -5
  123. package/src/tools/observability/check_ports.ts +1 -1
  124. package/src/tools/quality/check_lint.ts +2 -2
  125. package/src/tools/search/get_gaps.ts +1 -1
  126. package/src/tools/search/grep_search.ts +3 -3
  127. package/src/tools/types.ts +1 -1
  128. package/src/utils/compliance.ts +181 -5
  129. package/src/utils/permissions.ts +88 -0
  130. package/tsconfig.json +1 -2
  131. package/dist/utils/compliance.js +0 -78
  132. /package/dist/{tools → framework-mcp/src/tools}/framework/get_status.js +0 -0
  133. /package/dist/{tools → framework-mcp/src/tools}/framework/orchestrate.js +0 -0
  134. /package/dist/{tools → framework-mcp/src/tools}/framework/update_contract_hash.js +0 -0
  135. /package/dist/{tools → framework-mcp/src/tools}/memory/read_memory.js +0 -0
  136. /package/dist/{tools → framework-mcp/src/tools}/observability/get_health.js +0 -0
  137. /package/dist/{tools → framework-mcp/src/tools}/search/get_map.js +0 -0
  138. /package/dist/{tools → framework-mcp/src/tools}/search/list_dir.js +0 -0
  139. /package/dist/{tools → framework-mcp/src/tools}/shell/run_command.js +0 -0
  140. /package/dist/{tools → framework-mcp/src/tools}/types.js +0 -0
  141. /package/dist/{utils → framework-mcp/src/utils}/cli.js +0 -0
  142. /package/dist/{utils → framework-mcp/src/utils}/fs.js +0 -0
  143. /package/dist/{utils → framework-mcp/src/utils}/metrics.js +0 -0
  144. /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": ".antigravity/agents",
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: `❌ Unknown tool: ${name}` }],
92
+ content: [{ type: "text", text: `[ERROR] Unknown tool: ${name}` }],
69
93
  };
70
94
  }
71
- // 🛡️ Runtime Validation
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: `❌ Validation Error: ${validationError}` }],
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: `❌ Execution failed: ${message}` }],
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: `✅ Lock acquired for resource '${resource}' by ${agent}.` }]
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: `❌ Denied: You do not own the lock for '${resource}'. Owned by ${lockData.agent}.` }]
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: `✅ Lock released for resource '${resource}' by ${agent}.` }] };
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: `🎖️ Agent ${agent} (${role}) registered successfully in the Atabey Control Plane.` }]
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(`✅ Edited ${edit.path}`);
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
- export function handlePatchFile(projectRoot, args) {
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: `✅ File patched successfully: ${args.path}` }] };
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: `❌ ${err}` }] };
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: `❌ ${err}` }] };
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: `❌ ${err}` }] };
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
- export function handleReplaceText(projectRoot, args) {
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: `✅ Surgical edit successful in ${args.path}` }] };
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
- export function handleWriteFile(projectRoot, args) {
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: `❌ ${err}` }] };
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: `✅ File written: ${args.path}` }] };
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: `❌ ${err}` }] };
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(`⚠️ Potential redundancy in [${group}]: Found ${found.join(", ")}`);
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
- : " Dependencies look clean and consolidated."
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: `✅ Tests passed successfully for ${language}!\n\n${output}` }]
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: `❌ Tests FAILED for ${language}!\n\n--- STDOUT ---\n${stdout}\n\n--- STDERR ---\n${stderr}`
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: `✅ Section ${section} updated.` }] };
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 = `🧠 **Memory Insights**\n- **Phase:** ${activePhase}\n- **Trace:** ${activeTrace}\n\n**Recent Actions:**\n${recentHistory}`;
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: `✅ Action logged for ${agent} to ${path.join(frameworkDir, "logs", `${agentName}.json`)}` }] };
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: `❌ ${err}` }] };
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: `❌ Unexpected lock acquisition error: ${error.message || String(err)}` }], isError: true };
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: `❌ ${err}` }], isError: true };
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: `✅ Message sent to ${to} (from: ${from})` }] };
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: `❌ ${err}` }] };
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: `📡 **Active Listening Ports:**\n\n${output || "No active listening ports found matching filter."}`
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: `❌ Lint Errors Found (${language}):\n\n${output}` }]
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: `✅ Lint check passed successfully for ${language}:\n\n${output}` }]
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
- : " No major gaps or TODOs found in the scanned directory."
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: `❌ ${err}` }] };
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: `❌ ${err}` }] };
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: `❌ ${err}` }] };
65
+ return { isError: true, content: [{ type: "text", text: `[ERROR] ${err}` }] };
66
66
  }
67
67
  return {
68
68
  content: [{