agent-enderun 0.6.1 → 0.6.6

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 (89) hide show
  1. package/.enderun/BRAIN_DASHBOARD.md +12 -12
  2. package/.enderun/PROJECT_MEMORY.md +17 -17
  3. package/.enderun/STATUS.md +11 -11
  4. package/.enderun/agents/README.md +40 -0
  5. package/.enderun/agents/analyst.md +238 -31
  6. package/.enderun/agents/backend.md +428 -18
  7. package/.enderun/agents/explorer.md +169 -31
  8. package/.enderun/agents/frontend.md +604 -76
  9. package/.enderun/agents/git.md +153 -62
  10. package/.enderun/agents/manager.md +433 -46
  11. package/.enderun/agents/mobile.md +143 -29
  12. package/.enderun/agents/native.md +191 -28
  13. package/.enderun/blueprints/README.md +82 -0
  14. package/.enderun/blueprints/backend/errors/config/meta.json +11 -0
  15. package/.enderun/blueprints/backend/errors/domain-error.ts +34 -55
  16. package/.enderun/docs/README.md +50 -0
  17. package/.enderun/docs/phase1-reference-app-execution-plan.md +177 -0
  18. package/.enderun/docs/structure-audit-2026-05-24.md +72 -0
  19. package/.enderun/knowledge/README.md +22 -0
  20. package/.enderun/knowledge/database_governance_guidelines.md +118 -0
  21. package/.enderun/knowledge/deployment_checklist.md +132 -6
  22. package/.enderun/knowledge/documentation_ownership.md +122 -0
  23. package/.enderun/knowledge/documentation_ownership_status.md +122 -0
  24. package/.enderun/knowledge/enterprise_capabilities_reference.md +149 -0
  25. package/.enderun/knowledge/enterprise_frontend_adaptation.md +232 -0
  26. package/.enderun/knowledge/enterprise_project_adaptation.md +168 -0
  27. package/.enderun/knowledge/framework_vs_user_project_boundary.md +52 -0
  28. package/.enderun/knowledge/frontend_professionalization_guidelines.md +111 -0
  29. package/.enderun/knowledge/frontend_real_battle_test_protocol.md +162 -0
  30. package/.enderun/knowledge/hermes_live_test_guidelines.md +90 -0
  31. package/.enderun/knowledge/manager_authority_audit_enforcement.md +104 -0
  32. package/.enderun/knowledge/project_scaffold_guidelines.md +99 -0
  33. package/.enderun/knowledge/reference_application_guidelines.md +90 -0
  34. package/ENDERUN.md +19 -5
  35. package/README.md +132 -657
  36. package/antigravity.md +15 -0
  37. package/bin/cli.js +92 -27
  38. package/bin/hermes-sandbox.js +136 -0
  39. package/docs/README.md +33 -3
  40. package/docs/action-plan-2026.md +119 -0
  41. package/docs/getting-started.md +271 -0
  42. package/docs/roadmap.md +142 -0
  43. package/framework-mcp/README.md +1 -1
  44. package/framework-mcp/dist/index.js +0 -0
  45. package/framework-mcp/dist/schemas.js +6 -0
  46. package/framework-mcp/dist/tools/academy.js +6 -8
  47. package/framework-mcp/dist/tools/codebase.js +6 -6
  48. package/framework-mcp/dist/tools/contract.js +94 -4
  49. package/framework-mcp/dist/tools/database.js +8 -3
  50. package/framework-mcp/dist/tools/framework.js +7 -11
  51. package/framework-mcp/dist/tools/git.js +2 -2
  52. package/framework-mcp/dist/tools/knowledge.js +5 -5
  53. package/framework-mcp/dist/tools/memory.js +5 -7
  54. package/framework-mcp/dist/tools/messages.js +76 -16
  55. package/framework-mcp/dist/tools/repository.js +4 -4
  56. package/framework-mcp/dist/tools/scaffold.js +6 -3
  57. package/framework-mcp/dist/tools/security.js +4 -4
  58. package/framework-mcp/dist/utils.js +2 -2
  59. package/framework-mcp/package.json +1 -1
  60. package/framework-mcp/src/schemas.ts +7 -0
  61. package/framework-mcp/src/tools/academy.ts +5 -9
  62. package/framework-mcp/src/tools/codebase.ts +6 -6
  63. package/framework-mcp/src/tools/contract.ts +114 -4
  64. package/framework-mcp/src/tools/database.ts +8 -3
  65. package/framework-mcp/src/tools/framework.ts +8 -11
  66. package/framework-mcp/src/tools/git.ts +2 -2
  67. package/framework-mcp/src/tools/knowledge.ts +6 -7
  68. package/framework-mcp/src/tools/memory.ts +5 -6
  69. package/framework-mcp/src/tools/messages.ts +94 -28
  70. package/framework-mcp/src/tools/repository.ts +5 -6
  71. package/framework-mcp/src/tools/scaffold.ts +9 -6
  72. package/framework-mcp/src/tools/security.ts +4 -4
  73. package/framework-mcp/src/utils.ts +19 -2
  74. package/framework-mcp/tsconfig.json +1 -1
  75. package/gemini.md +4 -4
  76. package/package.json +11 -7
  77. package/panda.config.ts +3 -1
  78. package/.enderun/benchmarks/.gitkeep +0 -0
  79. package/.enderun/blueprints/backend/middleware/error-handler.ts +0 -24
  80. package/.enderun/blueprints/backend/types/api.ts +0 -20
  81. package/.enderun/blueprints/backend/types/brands.ts +0 -12
  82. package/.enderun/blueprints/backend/types/constants.ts +0 -34
  83. package/.enderun/blueprints/backend/types/index.ts +0 -49
  84. package/.enderun/blueprints/backend/types/logs.ts +0 -16
  85. package/.enderun/blueprints/backend/types/models.ts +0 -65
  86. package/.enderun/blueprints/frontend/ui/Button.tsx +0 -60
  87. package/.enderun/blueprints/frontend/ui/Input.tsx +0 -43
  88. package/.enderun/monitoring/.gitkeep +0 -0
  89. package/gemini-extension.json +0 -13
@@ -29,13 +29,18 @@ export const databaseHandlers = {
29
29
  for (const sourceFile of tsProject.getSourceFiles()) {
30
30
  const text = sourceFile.getFullText();
31
31
  const tableMatches = Array.from(text.matchAll(/\.createTable\(['"]([^'"]+)['"]\)/g));
32
- for (const match of tableMatches) {
32
+ for (let i = 0; i < tableMatches.length; i++) {
33
+ const match = tableMatches[i];
33
34
  const tableName = match[1];
34
35
  tablesFound++;
35
36
  mermaid += ` ${tableName} {\n`;
37
+ const startIndex = match.index ?? 0;
38
+ const nextMatch = tableMatches[i + 1];
39
+ const endIndex = nextMatch ? (nextMatch.index ?? text.length) : text.length;
40
+ const tableBlockText = text.substring(startIndex, endIndex);
36
41
  const colRegex = /\.addColumn\(['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]/g;
37
42
  let colMatch;
38
- while ((colMatch = colRegex.exec(text)) !== null) {
43
+ while ((colMatch = colRegex.exec(tableBlockText)) !== null) {
39
44
  mermaid += ` ${colMatch[2].replace(/[^a-zA-Z0-9]/g, '_')} ${colMatch[1]}\n`;
40
45
  }
41
46
  mermaid += ` }\n`;
@@ -45,7 +50,7 @@ export const databaseHandlers = {
45
50
  return { content: [{ type: "text", text: "No database tables detected." }] };
46
51
  return { content: [{ type: "text", text: `### DATABASE SCHEMA MAP\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`\n\n**Total Tables Detected:** ${tablesFound}` }] };
47
52
  }
48
- catch (error) {
53
+ catch {
49
54
  return { content: [{ type: "text", text: "Database schema analysis failed." }] };
50
55
  }
51
56
  },
@@ -2,7 +2,6 @@ import fs from "fs";
2
2
  import path from "path";
3
3
  import { execSync } from "child_process";
4
4
  import { getFrameworkDir, collectMarkdownArtifacts, FRAMEWORK_VERSION } from "../utils.js";
5
- import { VERIFY_FRAMEWORK_HEALTH_ARGS_SCHEMA } from "../schemas.js";
6
5
  export const frameworkTools = [
7
6
  {
8
7
  name: "get_framework_status",
@@ -70,8 +69,6 @@ export const frameworkHandlers = {
70
69
  if (detected.length > 0)
71
70
  techStack = detected.join(", ");
72
71
  }
73
- const rootDirs = fs.readdirSync(projectRoot).filter(f => fs.lstatSync(path.join(projectRoot, f)).isDirectory() && !f.startsWith("."));
74
- const isMonorepo = rootDirs.includes("apps") || rootDirs.includes("packages");
75
72
  const date = new Date().toISOString().split("T")[0];
76
73
  const bootstrapContent = `# PROJECT MEMORY — Legacy Onboarding\n\n## CURRENT STATUS\n\n| Active Phase | Profile | Last Update | Active Trace ID | Blockers |\n| PHASE_1 | Full | ${date} | — | Legacy Onboarding |`;
77
74
  if (fs.existsSync(memoryPath))
@@ -79,7 +76,7 @@ export const frameworkHandlers = {
79
76
  fs.writeFileSync(memoryPath, bootstrapContent);
80
77
  return { content: [{ type: "text", text: `Legacy Codebase Bootstrap complete. Detected Stack: ${techStack}.` }] };
81
78
  }
82
- catch (error) {
79
+ catch {
83
80
  return { content: [{ type: "text", text: "Failed to bootstrap legacy memory." }] };
84
81
  }
85
82
  },
@@ -95,8 +92,8 @@ export const frameworkHandlers = {
95
92
  content: [{ type: "text", text: `Framework active (v${FRAMEWORK_VERSION}). Phase: ${phase}. Profile: ${profile}.` }],
96
93
  };
97
94
  }
98
- catch (error) {
99
- return { content: [{ type: "text", text: "Framework active. Memory unreadable." }] };
95
+ catch {
96
+ return { content: [{ type: "text", text: "Failed to get framework status." }] };
100
97
  }
101
98
  },
102
99
  get_project_gaps: async (args, projectRoot) => {
@@ -150,8 +147,8 @@ export const frameworkHandlers = {
150
147
  content: [{ type: "text", text: `### LIVE MEMORY INSIGHTS\n\n**Active Tasks:**\n${activeTasks.trim()}\n\n**Recent History:**\n${history.trim().substring(0, 1000)}...\n\n**Brain Snapshot:**\n${dashboardAgents.trim().substring(0, 500)}...` }],
151
148
  };
152
149
  }
153
- catch (error) {
154
- return { content: [{ type: "text", text: "Failed to gather memory insights." }] };
150
+ catch {
151
+ return { content: [{ type: "text", text: "Failed to get memory insights." }] };
155
152
  }
156
153
  },
157
154
  codebase_context: async (args, projectRoot) => {
@@ -164,15 +161,14 @@ export const frameworkHandlers = {
164
161
  content: [{ type: "text", text: "### CONTEXT ARTIFACTS\n\n" + `PROJECT_MEMORY: ${fs.existsSync(memoryPath) ? "present" : "missing"}\n` + `BRAIN_DASHBOARD: ${fs.existsSync(dashboardPath) ? "present" : "missing"}\n` + `Docs:\n${artifacts.length > 0 ? artifacts.join("\n") : "No markdown artifacts found."}` }],
165
162
  };
166
163
  }
167
- catch (error) {
168
- return { content: [{ type: "text", text: "Context discovery failed." }] };
164
+ catch {
165
+ return { content: [{ type: "text", text: "Failed to gather codebase context." }] };
169
166
  }
170
167
  },
171
168
  get_system_time: async () => {
172
169
  return { content: [{ type: "text", text: new Date().toISOString() }] };
173
170
  },
174
171
  verify_framework_health: async (args, projectRoot) => {
175
- const parsed = VERIFY_FRAMEWORK_HEALTH_ARGS_SCHEMA.safeParse(args ?? {});
176
172
  try {
177
173
  // Run the internal CLI check command via tsx to ensure we test current state
178
174
  // If the CLI is not yet linked, we might need a relative path
@@ -44,8 +44,8 @@ export const gitHandlers = {
44
44
  const summary = files.length === 1 ? `update ${path.basename(files[0])}` : `update ${files.length} files`;
45
45
  return { content: [{ type: "text", text: `### SUGGESTED SEMANTIC COMMIT MESSAGE\n\n\`[${parsed.data.traceId}] ${type}(${scope}): ${summary}\`\n\n**Files Analyzed:**\n${files.map(f => `- ${f}`).join("\n")}` }] };
46
46
  }
47
- catch (error) {
48
- return { content: [{ type: "text", text: "Failed to generate commit message." }] };
47
+ catch {
48
+ return { content: [{ type: "text", text: "Failed to generate semantic commit message." }] };
49
49
  }
50
50
  },
51
51
  };
@@ -76,7 +76,7 @@ export const knowledgeHandlers = {
76
76
  }).filter(Boolean);
77
77
  return { content: [{ type: "text", text: results.length > 0 ? `### KNOWLEDGE BASE SEARCH RESULTS\n\n${results.join("\n\n---\n\n")}` : "No matching knowledge entries found." }] };
78
78
  }
79
- catch (error) {
79
+ catch {
80
80
  return { content: [{ type: "text", text: "Knowledge base search failed." }] };
81
81
  }
82
82
  },
@@ -90,7 +90,7 @@ export const knowledgeHandlers = {
90
90
  if (!fs.existsSync(kbDir))
91
91
  fs.mkdirSync(kbDir, { recursive: true });
92
92
  const fileName = parsed.data.topic.replace(/[^a-z0-9]/gi, "_").toLowerCase() + ".md";
93
- const tags = parsed.data.tags;
93
+ const tags = parsed.data.tags || [];
94
94
  let finalContent = parsed.data.content;
95
95
  if (!finalContent.startsWith("---")) {
96
96
  const frontmatter = `---\ntitle: ${parsed.data.topic}\ntags: [${tags.join(", ")}]\nlast_updated: ${new Date().toISOString()}\n---\n\n`;
@@ -99,7 +99,7 @@ export const knowledgeHandlers = {
99
99
  fs.writeFileSync(path.join(kbDir, fileName), finalContent);
100
100
  return { content: [{ type: "text", text: `Obsidian Wiki updated: ${parsed.data.topic}` }] };
101
101
  }
102
- catch (error) {
102
+ catch {
103
103
  return { content: [{ type: "text", text: "Failed to update knowledge base." }] };
104
104
  }
105
105
  },
@@ -126,8 +126,8 @@ export const knowledgeHandlers = {
126
126
  });
127
127
  return { content: [{ type: "text", text: `### KNOWLEDGE GRAPH (Mermaid)\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`` }] };
128
128
  }
129
- catch (error) {
130
- return { content: [{ type: "text", text: "Failed to generate knowledge graph." }] };
129
+ catch {
130
+ return { content: [{ type: "text", text: "Failed to get knowledge graph." }] };
131
131
  }
132
132
  }
133
133
  };
@@ -57,7 +57,7 @@ export const memoryHandlers = {
57
57
  updated = true;
58
58
  break;
59
59
  }
60
- catch (e) {
60
+ catch {
61
61
  // Ignore section not found
62
62
  }
63
63
  }
@@ -75,10 +75,8 @@ export const memoryHandlers = {
75
75
  fs.unlinkSync(lockPath);
76
76
  return { content: [{ type: "text", text: `Section ${section} updated successfully.` }] };
77
77
  }
78
- catch (error) {
79
- if (fs.existsSync(lockPath) && fs.readFileSync(lockPath, "utf-8").includes(lockOwner))
80
- fs.unlinkSync(lockPath);
81
- return { content: [{ type: "text", text: `Memory update failed: ${error instanceof Error ? error.message : "Unknown error"}` }] };
78
+ catch {
79
+ return { content: [{ type: "text", text: "Failed to update project memory." }] };
82
80
  }
83
81
  },
84
82
  read_project_memory: async (args, projectRoot) => {
@@ -89,8 +87,8 @@ export const memoryHandlers = {
89
87
  return { content: [{ type: "text", text: `ERROR: ${frameworkDir}/PROJECT_MEMORY.md not found.` }] };
90
88
  return { content: [{ type: "text", text: fs.readFileSync(memoryPath, "utf-8") }] };
91
89
  }
92
- catch (error) {
93
- return { content: [{ type: "text", text: "ERROR: Failed to read PROJECT_MEMORY.md" }] };
90
+ catch {
91
+ return { content: [{ type: "text", text: "Failed to read project memory." }] };
94
92
  }
95
93
  },
96
94
  };
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { getFrameworkDir } from "../utils.js";
4
- import { SEND_AGENT_MESSAGE_ARGS_SCHEMA, READ_AGENT_MESSAGES_ARGS_SCHEMA, GET_AGENT_INBOX_STATS_ARGS_SCHEMA } from "../schemas.js";
4
+ import { SEND_AGENT_MESSAGE_ARGS_SCHEMA, READ_AGENT_MESSAGES_ARGS_SCHEMA, GET_AGENT_INBOX_STATS_ARGS_SCHEMA, UPDATE_AGENT_MESSAGE_STATUS_ARGS_SCHEMA } from "../schemas.js";
5
5
  export const messageTools = [
6
6
  {
7
7
  name: "send_agent_message",
@@ -9,13 +9,14 @@ export const messageTools = [
9
9
  inputSchema: {
10
10
  type: "object",
11
11
  properties: {
12
+ from: { type: "string", description: "Sender agent name (e.g. @manager, @backend)" },
12
13
  to: { type: "string", description: "Recipient agent name" },
13
14
  message: { type: "string", description: "The message content" },
14
15
  traceId: { type: "string", description: "The active Trace ID" },
15
16
  category: { type: "string", enum: ["ACTION", "DELEGATION", "INFO", "ALERT"], default: "INFO" },
16
17
  priority: { type: "string", enum: ["LOW", "MEDIUM", "HIGH", "URGENT"], default: "MEDIUM" },
17
18
  },
18
- required: ["to", "message", "traceId"],
19
+ required: ["from", "to", "message", "traceId"],
19
20
  },
20
21
  },
21
22
  {
@@ -41,6 +42,19 @@ export const messageTools = [
41
42
  required: ["agent"],
42
43
  },
43
44
  },
45
+ {
46
+ name: "update_agent_message_status",
47
+ description: "Allows an agent to acknowledge, complete, or reject a Hermes message by Trace ID (advances the orchestration lifecycle).",
48
+ inputSchema: {
49
+ type: "object",
50
+ properties: {
51
+ agent: { type: "string", description: "The agent performing the status update" },
52
+ traceId: { type: "string", description: "Trace ID of the message to update" },
53
+ newStatus: { type: "string", enum: ["ACKNOWLEDGED", "COMPLETED", "REJECTED"], description: "New lifecycle status" },
54
+ },
55
+ required: ["agent", "traceId", "newStatus"],
56
+ },
57
+ },
44
58
  ];
45
59
  function normalizeAgentName(agent) {
46
60
  const normalized = agent.replace(/^@/, "").trim();
@@ -61,20 +75,22 @@ export const messageHandlers = {
61
75
  fs.mkdirSync(messagesDir, { recursive: true });
62
76
  const messagePath = path.join(messagesDir, `${recipient}.json`);
63
77
  const messages = (fs.existsSync(messagePath) ? JSON.parse(fs.readFileSync(messagePath, "utf-8")) : []);
78
+ const sender = normalizeAgentName(parsed.data.from) || "unknown";
64
79
  messages.push({
65
80
  timestamp: new Date().toISOString(),
66
- from: "manager",
81
+ from: sender,
82
+ to: recipient,
67
83
  traceId: parsed.data.traceId,
68
84
  category: parsed.data.category,
69
85
  priority: parsed.data.priority,
70
86
  content: parsed.data.message,
71
- read: false
87
+ status: "PENDING"
72
88
  });
73
89
  fs.writeFileSync(messagePath, JSON.stringify(messages, null, 2));
74
90
  return { content: [{ type: "text", text: `Hermes: Message sent to @${recipient} [${parsed.data.category} | ${parsed.data.priority}].` }] };
75
91
  }
76
- catch (error) {
77
- return { content: [{ type: "text", text: "Failed to send message via Hermes." }] };
92
+ catch {
93
+ return { content: [{ type: "text", text: "Failed to send agent message." }] };
78
94
  }
79
95
  },
80
96
  read_agent_messages: async (args, projectRoot) => {
@@ -90,15 +106,24 @@ export const messageHandlers = {
90
106
  if (!fs.existsSync(messagePath))
91
107
  return { content: [{ type: "text", text: "No messages found." }] };
92
108
  const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
93
- const unread = messages.filter((m) => !m.read && (!parsed.data.traceId || m.traceId === parsed.data.traceId));
94
- fs.writeFileSync(messagePath, JSON.stringify(messages.map((m) => (!m.read && (!parsed.data.traceId || m.traceId === parsed.data.traceId) ? { ...m, read: true } : m)), null, 2));
95
- if (unread.length === 0)
109
+ const pending = messages.filter((m) => (m.status === "PENDING" || m.status === "ACKNOWLEDGED") &&
110
+ (!parsed.data.traceId || m.traceId === parsed.data.traceId));
111
+ // Transition PENDING → READ (Do not regress ACKNOWLEDGED messages back to READ)
112
+ const updated = messages.map((m) => {
113
+ if (m.status === "PENDING" &&
114
+ (!parsed.data.traceId || m.traceId === parsed.data.traceId)) {
115
+ return { ...m, status: "READ" };
116
+ }
117
+ return m;
118
+ });
119
+ fs.writeFileSync(messagePath, JSON.stringify(updated, null, 2));
120
+ if (pending.length === 0)
96
121
  return { content: [{ type: "text", text: "No new messages." }] };
97
- const formatted = unread.map((m) => `- [${m.priority}] **${m.from}** (${m.category}): ${m.content} *(Trace: ${m.traceId})*`).join("\n");
122
+ const formatted = pending.map((m) => `- [${m.priority}] **${m.from}** (${m.category}): ${m.content} *(Trace: ${m.traceId})*`).join("\n");
98
123
  return { content: [{ type: "text", text: `### HERMES INBOX: @${agentName}\n\n${formatted}` }] };
99
124
  }
100
- catch (error) {
101
- return { content: [{ type: "text", text: "Failed to read messages." }] };
125
+ catch {
126
+ return { content: [{ type: "text", text: "Failed to send agent message." }] };
102
127
  }
103
128
  },
104
129
  get_agent_inbox_stats: async (args, projectRoot) => {
@@ -114,20 +139,55 @@ export const messageHandlers = {
114
139
  if (!fs.existsSync(messagePath))
115
140
  return { content: [{ type: "text", text: "Inbox empty." }] };
116
141
  const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
117
- const unread = messages.filter(m => !m.read);
142
+ const pendingOrRead = messages.filter(m => m.status === "PENDING" || m.status === "READ");
118
143
  const priorityDist = messages.reduce((acc, m) => {
119
144
  acc[m.priority] = (acc[m.priority] || 0) + 1;
120
145
  return acc;
121
146
  }, {});
147
+ const statusDist = messages.reduce((acc, m) => {
148
+ acc[m.status] = (acc[m.status] || 0) + 1;
149
+ return acc;
150
+ }, {});
122
151
  return {
123
152
  content: [{
124
153
  type: "text",
125
- text: `### INBOX STATS: @${agentName}\n- Total: ${messages.length}\n- Unread: ${unread.length}\n- Priority Distribution: ${JSON.stringify(priorityDist)}`
154
+ text: `### INBOX STATS: @${agentName}\n- Total: ${messages.length}\n- Pending/Read: ${pendingOrRead.length}\n- By Priority: ${JSON.stringify(priorityDist)}\n- By Status: ${JSON.stringify(statusDist)}`
126
155
  }]
127
156
  };
128
157
  }
129
- catch (error) {
130
- return { content: [{ type: "text", text: "Failed to get inbox stats." }] };
158
+ catch {
159
+ return { content: [{ type: "text", text: "Failed to read agent messages." }] };
160
+ }
161
+ },
162
+ update_agent_message_status: async (args, projectRoot) => {
163
+ const parsed = UPDATE_AGENT_MESSAGE_STATUS_ARGS_SCHEMA.safeParse(args ?? {});
164
+ if (!parsed.success)
165
+ return { content: [{ type: "text", text: "Invalid arguments for status update." }] };
166
+ try {
167
+ const frameworkDir = getFrameworkDir(projectRoot);
168
+ const agentName = normalizeAgentName(parsed.data.agent);
169
+ if (!agentName)
170
+ return { content: [{ type: "text", text: "Invalid agent name." }] };
171
+ const messagePath = path.join(projectRoot, frameworkDir, "messages", `${agentName}.json`);
172
+ if (!fs.existsSync(messagePath))
173
+ return { content: [{ type: "text", text: "No messages for this agent." }] };
174
+ const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
175
+ let updated = false;
176
+ const newMessages = messages.map((m) => {
177
+ if (m.traceId === parsed.data.traceId) {
178
+ updated = true;
179
+ return { ...m, status: parsed.data.newStatus };
180
+ }
181
+ return m;
182
+ });
183
+ if (!updated) {
184
+ return { content: [{ type: "text", text: `No message found with Trace ID ${parsed.data.traceId}.` }] };
185
+ }
186
+ fs.writeFileSync(messagePath, JSON.stringify(newMessages, null, 2));
187
+ return { content: [{ type: "text", text: `Hermes: Message ${parsed.data.traceId} marked as ${parsed.data.newStatus}.` }] };
188
+ }
189
+ catch {
190
+ return { content: [{ type: "text", text: "Failed to update message status." }] };
131
191
  }
132
192
  }
133
193
  };
@@ -66,8 +66,8 @@ export const repositoryHandlers = {
66
66
  results.push(runScript("build"));
67
67
  return { content: [{ type: "text", text: `### REPOSITORY HEALTH REPORT\n\n` + results.map(r => `- **${r.name.toUpperCase()}** (${r.script}): ${r.status}${r.status === "FAILED" && r.details ? `\n ${r.details}` : ""}`).join("\n") }] };
68
68
  }
69
- catch (error) {
70
- return { content: [{ type: "text", text: "Health validation failed." }] };
69
+ catch {
70
+ return { content: [{ type: "text", text: "Failed to analyze repository health." }] };
71
71
  }
72
72
  },
73
73
  analyze_documentation_debt: async (args, projectRoot) => {
@@ -94,8 +94,8 @@ export const repositoryHandlers = {
94
94
  const majorDirs = ["apps/backend", "apps/web", "framework-mcp"], missingREADME = majorDirs.filter(dir => fs.existsSync(path.join(projectRoot, dir)) && !fs.existsSync(path.join(projectRoot, dir, "README.md")));
95
95
  return { content: [{ type: "text", text: `### DOCUMENTATION DEBT REPORT\n\n**Missing JSDoc:**\n${missingJSDoc.slice(0, 10).join("\n")}\n\n**Missing README.md:**\n${missingREADME.join("\n")}` }] };
96
96
  }
97
- catch (error) {
98
- return { content: [{ type: "text", text: "Documentation debt scan failed." }] };
97
+ catch {
98
+ return { content: [{ type: "text", text: "Failed to analyze documentation debt." }] };
99
99
  }
100
100
  },
101
101
  };
@@ -60,7 +60,8 @@ export const scaffoldHandlers = {
60
60
  return { content: [{ type: "text", text: `Successfully instantiated blueprint '${blueprintPath}' into '${targetPath}'` }] };
61
61
  }
62
62
  catch (error) {
63
- return { content: [{ type: "text", text: `Scaffold failed: ${error.message}` }] };
63
+ const message = error instanceof Error ? error.message : "Unknown error";
64
+ return { content: [{ type: "text", text: `Scaffold failed: ${message}` }] };
64
65
  }
65
66
  },
66
67
  save_as_blueprint: async (args, projectRoot) => {
@@ -83,7 +84,8 @@ export const scaffoldHandlers = {
83
84
  return { content: [{ type: "text", text: `Successfully saved blueprint to '${blueprintPath}'` }] };
84
85
  }
85
86
  catch (error) {
86
- return { content: [{ type: "text", text: `Failed to save blueprint: ${error.message}` }] };
87
+ const message = error instanceof Error ? error.message : "Unknown error";
88
+ return { content: [{ type: "text", text: `Failed to save blueprint: ${message}` }] };
87
89
  }
88
90
  },
89
91
  list_blueprints: async (args, projectRoot) => {
@@ -123,7 +125,8 @@ export const scaffoldHandlers = {
123
125
  return { content: [{ type: "text", text: `### AVAILABLE BLUEPRINTS\n\n` + available.map(b => `- ${b}`).join("\n") }] };
124
126
  }
125
127
  catch (error) {
126
- return { content: [{ type: "text", text: `Listing blueprints failed: ${error.message}` }] };
128
+ const message = error instanceof Error ? error.message : "Unknown error";
129
+ return { content: [{ type: "text", text: `Listing blueprints failed: ${message}` }] };
127
130
  }
128
131
  },
129
132
  };
@@ -77,8 +77,8 @@ export const securityHandlers = {
77
77
  }
78
78
  return { content: [{ type: "text", text: vulnerabilities.length > 0 ? `### ADVANCED SECURITY AUDIT RESULTS\n\n${Array.from(new Set(vulnerabilities)).join("\n\n")}` : "No security patterns or rule violations detected (Regex & AST verified)." }] };
79
79
  }
80
- catch (error) {
81
- return { content: [{ type: "text", text: "Security scan failed." }] };
80
+ catch {
81
+ return { content: [{ type: "text", text: "Security audit failed." }] };
82
82
  }
83
83
  },
84
84
  analyze_constitution_compliance: async (args, projectRoot) => {
@@ -130,8 +130,8 @@ export const securityHandlers = {
130
130
  }
131
131
  return { content: [{ type: "text", text: `### CONSTITUTION COMPLIANCE REPORT\n\n` + (violations.length > 0 ? `⚠️ **VIOLATIONS FOUND:**\n${violations.map(v => `- ${v}`).join("\n")}` : "✅ **ALL SYSTEMS COMPLIANT:** AST and Regex scans passed. No rule violations detected.") }] };
132
132
  }
133
- catch (error) {
134
- return { content: [{ type: "text", text: "Compliance analysis failed." }] };
133
+ catch {
134
+ return { content: [{ type: "text", text: "Constitution compliance check failed." }] };
135
135
  }
136
136
  },
137
137
  };
@@ -1,8 +1,8 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- export const FRAMEWORK_VERSION = "0.6.1";
3
+ export const FRAMEWORK_VERSION = "0.6.5";
4
4
  export function getFrameworkDir(projectRoot) {
5
- const adapters = [".gemini", ".claude", ".cursor", ".enderun", ".codex"];
5
+ const adapters = [".antigravitycli", ".claude", ".cursor", ".enderun", ".codex"];
6
6
  for (const adp of adapters) {
7
7
  const fullPath = path.join(projectRoot, adp);
8
8
  if (fs.existsSync(fullPath) && fs.lstatSync(fullPath).isDirectory()) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-enderun-mcp",
3
- "version": "0.6.1",
3
+ "version": "0.6.6",
4
4
  "description": "Enterprise-grade MCP Server for AI Agent Framework",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -32,6 +32,7 @@ export const LOG_AGENT_ACTION_ARGS_SCHEMA = z.object({
32
32
  });
33
33
 
34
34
  export const SEND_AGENT_MESSAGE_ARGS_SCHEMA = z.object({
35
+ from: z.string().min(1),
35
36
  to: z.string().min(1),
36
37
  message: z.string().min(1),
37
38
  traceId: z.string().min(1),
@@ -39,6 +40,12 @@ export const SEND_AGENT_MESSAGE_ARGS_SCHEMA = z.object({
39
40
  priority: z.enum(["LOW", "MEDIUM", "HIGH", "URGENT"]).default("MEDIUM"),
40
41
  });
41
42
 
43
+ export const UPDATE_AGENT_MESSAGE_STATUS_ARGS_SCHEMA = z.object({
44
+ agent: z.string().min(1),
45
+ traceId: z.string().min(1),
46
+ newStatus: z.enum(["ACKNOWLEDGED", "COMPLETED", "REJECTED"]),
47
+ });
48
+
42
49
  export const SEARCH_KNOWLEDGE_BASE_ARGS_SCHEMA = z.object({
43
50
  query: z.string().min(1),
44
51
  });
@@ -3,8 +3,6 @@ import path from "path";
3
3
  import { getFrameworkDir } from "../utils.js";
4
4
  import {
5
5
  GET_ACADEMY_PERFORMANCE_ARGS_SCHEMA,
6
- GENERATE_STRATEGIC_BRIEFING_ARGS_SCHEMA,
7
- GENERATE_ACADEMY_PROGRESS_REPORT_ARGS_SCHEMA,
8
6
  GET_AGENT_AUDIT_REPORT_ARGS_SCHEMA,
9
7
  LOG_AGENT_ACTION_ARGS_SCHEMA
10
8
  } from "../schemas.js";
@@ -112,7 +110,7 @@ export const academyHandlers = {
112
110
  return { agent: file.replace(".json", ""), actions: logs.length, successRate: (success / (logs.length || 1)) * 100 };
113
111
  }).filter(s => s.actions > 0);
114
112
  return { content: [{ type: "text", text: `### GLOBAL ACADEMY PERFORMANCE REPORT\n\n- **Analysis Period:** Last ${days} days\n- **Global Success Rate:** ${((totalSuccess / (totalActions || 1)) * 100).toFixed(1)}%\n\n**Agent Breakdown:**\n` + agentStats.map(s => `- **@${s.agent}:** ${s.actions} actions (${s.successRate.toFixed(1)}% success)`).join("\n") }] };
115
- } catch (error) {
113
+ } catch {
116
114
  return { content: [{ type: "text", text: "Failed to generate global performance report." }] };
117
115
  }
118
116
  },
@@ -129,13 +127,11 @@ export const academyHandlers = {
129
127
  }
130
128
  const successRate = (successCount / (totalActions || 1)) * 100;
131
129
  return { content: [{ type: "text", text: `# 🏛️ ACADEMY STRATEGIC BRIEFING\n\n- **Academy Health:** ${successRate.toFixed(1)}% Success Rate over ${totalActions} actions.\n**Status:** READY FOR PHASE_1 COMPLETION.` }] };
132
- } catch (error) {
130
+ } catch {
133
131
  return { content: [{ type: "text", text: "Strategic briefing generation failed." }] };
134
132
  }
135
133
  },
136
134
  generate_academy_progress_report: async (args: unknown, projectRoot: string) => {
137
- const parsed = GENERATE_ACADEMY_PROGRESS_REPORT_ARGS_SCHEMA.safeParse(args ?? {});
138
- const days = parsed.success ? parsed.data.days : 7;
139
135
  try {
140
136
  const frameworkDir = getFrameworkDir(projectRoot);
141
137
  const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
@@ -143,7 +139,7 @@ export const academyHandlers = {
143
139
  const historySection = memoryContent.match(/## HISTORY[\s\S]*$/m)?.[0] ?? "";
144
140
  const milestones = Array.from(historySection.matchAll(/### (.*)\n\n- \*\*Agent:\*\* (.*)\n- \*\*Trace ID:\*\* (.*)\n- \*\*Action:\*\* (.*)/g)).slice(0, 5).map(m => `- [${m[1]}] **${m[2]}:** ${m[4]}`).join("\n");
145
141
  return { content: [{ type: "text", text: `# 🎓 AGENT ACADEMY PROGRESS REPORT\n\n## 🏆 Key Milestones Achieved\n${milestones}` }] };
146
- } catch (error) {
142
+ } catch {
147
143
  return { content: [{ type: "text", text: "Failed to generate progress report." }] };
148
144
  }
149
145
  },
@@ -158,7 +154,7 @@ export const academyHandlers = {
158
154
  const logs = (JSON.parse(fs.readFileSync(logPath, "utf-8")) as AgentLog[]).filter((l) => new Date(l.timestamp) >= cutoff);
159
155
  const successCount = logs.filter((l) => l.status === "SUCCESS").length;
160
156
  return { content: [{ type: "text", text: `### AGENT AUDIT REPORT: ${parsed.data.agent.toUpperCase()}\n\n- **Total Actions:** ${logs.length}\n- **Success Rate:** ${((successCount / (logs.length || 1)) * 100).toFixed(1)}%` }] };
161
- } catch (error) {
157
+ } catch {
162
158
  return { content: [{ type: "text", text: "Failed to generate audit report." }] };
163
159
  }
164
160
  },
@@ -177,7 +173,7 @@ export const academyHandlers = {
177
173
  logs.push({ timestamp: new Date().toISOString(), ...parsed.data });
178
174
  fs.writeFileSync(logPath, JSON.stringify(logs, null, 2));
179
175
  return { content: [{ type: "text", text: `SUCCESS: Logged action to ${parsed.data.agent}.json` }] };
180
- } catch (error) {
176
+ } catch {
181
177
  return { content: [{ type: "text", text: "Failed to log action." }] };
182
178
  }
183
179
  },
@@ -145,7 +145,7 @@ export const codebaseHandlers = {
145
145
  let queryRegex: RegExp;
146
146
  try {
147
147
  queryRegex = new RegExp(query, "i");
148
- } catch (error) {
148
+ } catch {
149
149
  return { content: [{ type: "text", text: "Invalid regex pattern in query." }] };
150
150
  }
151
151
  const matches: string[] = [];
@@ -164,7 +164,7 @@ export const codebaseHandlers = {
164
164
  }
165
165
  }
166
166
  return { content: [{ type: "text", text: matches.join("\n") || "No matches found." }] };
167
- } catch (error) {
167
+ } catch {
168
168
  return { content: [{ type: "text", text: "Search failed." }] };
169
169
  }
170
170
  },
@@ -223,7 +223,7 @@ export const codebaseHandlers = {
223
223
  });
224
224
  }
225
225
  return { content: [{ type: "text", text: `### CODEBASE INTELLIGENCE REPORT\n\n**Complexity Spikes (>300 lines):**\n${complexitySpikes.length > 0 ? complexitySpikes.map(s => `- ${s}`).join("\n") : "- None detected"}\n\n**Potential Dead Code (Unused Exports):**\n${potentialDeadCode.length > 0 ? potentialDeadCode.map(d => `- ${d}`).join("\n") : "- None detected (within scanned scope)"}` }] };
226
- } catch (error) {
226
+ } catch {
227
227
  return { content: [{ type: "text", text: "Intelligence scan failed." }] };
228
228
  }
229
229
  },
@@ -247,8 +247,8 @@ export const codebaseHandlers = {
247
247
  const referenceFunctions = referenceFile.getFunctions().map(f => f.getName());
248
248
  if (referenceFunctions.some(f => f?.startsWith("get")) && !targetFunctions.some(f => f?.startsWith("get"))) deviations.push("Reference uses 'get' prefix for functions, target does not.");
249
249
  return { content: [{ type: "text", text: deviations.length > 0 ? `### PROCEDURAL CONTINUITY DEVIATIONS\n\n${deviations.map(d => `- ${d}`).join("\n")}` : "No major structural or stylistic deviations detected based on reference." }] };
250
- } catch (error) {
251
- return { content: [{ type: "text", text: "Continuity analysis failed." }] };
250
+ } catch {
251
+ return { content: [{ type: "text", text: "Dependency analysis failed." }] };
252
252
  }
253
253
  },
254
254
  generate_dependency_graph: async (args: unknown, projectRoot: string) => {
@@ -277,7 +277,7 @@ export const codebaseHandlers = {
277
277
  if (uniqueEdges.length === 0) return { content: [{ type: "text", text: "No internal dependencies found in the scanned path." }] };
278
278
  mermaid += uniqueEdges.join("\n");
279
279
  return { content: [{ type: "text", text: `### VISUAL ARCHITECTURE MAP: ${targetPath}\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`\n\n**Total Nodes:** ${new Set(edges.flatMap(e => [e.from, e.to])).size} | **Total Edges:** ${uniqueEdges.length}` }] };
280
- } catch (error) {
280
+ } catch {
281
281
  return { content: [{ type: "text", text: "Dependency graph generation failed." }] };
282
282
  }
283
283
  },