agent-enderun 0.6.0 → 0.6.5
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/.enderun/PROJECT_MEMORY.md +117 -3
- package/.enderun/STATUS.md +4 -4
- package/.enderun/agents/analyst.md +98 -12
- package/.enderun/agents/backend.md +258 -14
- package/.enderun/agents/explorer.md +67 -2
- package/.enderun/agents/frontend.md +404 -66
- package/.enderun/agents/git.md +19 -2
- package/.enderun/agents/manager.md +412 -45
- package/.enderun/agents/mobile.md +63 -19
- package/.enderun/agents/native.md +61 -11
- package/.enderun/blueprints/backend/errors/blueprint.json +11 -0
- package/.enderun/blueprints/backend/errors/domain-error.ts +34 -55
- package/.enderun/docs/tech-stack.md +7 -8
- package/.enderun/knowledge/contract_versioning.md +1 -1
- package/.enderun/knowledge/framework_vs_user_project_boundary.md +52 -0
- package/.enderun/knowledge/frontend_professionalization_guidelines.md +108 -0
- package/.enderun/knowledge/hermes_live_test_guidelines.md +90 -0
- package/.enderun/knowledge/manager_authority_audit_enforcement.md +104 -0
- package/.enderun/knowledge/project_scaffold_guidelines.md +99 -0
- package/.enderun/knowledge/reference_application_guidelines.md +90 -0
- package/.enderun/messages/2026-05-23-backend-to-manager-auth-errors-reply.json +23 -0
- package/.enderun/messages/2026-05-23-manager-to-backend-auth-errors.json +26 -0
- package/ENDERUN.md +12 -4
- package/README.md +185 -626
- package/antigravity.md +15 -0
- package/bin/cli.js +105 -30
- package/bin/update-contract.js +2 -2
- package/docs/README.md +33 -3
- package/docs/getting-started.md +497 -0
- package/docs/roadmap.md +200 -0
- package/framework-mcp/README.md +1 -1
- package/framework-mcp/dist/index.js +0 -0
- package/framework-mcp/dist/tools/academy.js +6 -8
- package/framework-mcp/dist/tools/codebase.js +6 -6
- package/framework-mcp/dist/tools/contract.js +94 -4
- package/framework-mcp/dist/tools/database.js +1 -1
- package/framework-mcp/dist/tools/framework.js +8 -12
- package/framework-mcp/dist/tools/git.js +2 -2
- package/framework-mcp/dist/tools/knowledge.js +4 -4
- package/framework-mcp/dist/tools/memory.js +5 -7
- package/framework-mcp/dist/tools/messages.js +6 -6
- package/framework-mcp/dist/tools/repository.js +4 -4
- package/framework-mcp/dist/tools/scaffold.js +6 -3
- package/framework-mcp/dist/tools/security.js +4 -4
- package/framework-mcp/dist/utils.js +2 -2
- package/framework-mcp/package.json +1 -1
- package/framework-mcp/src/schemas.ts +7 -0
- package/framework-mcp/src/tools/academy.ts +5 -9
- package/framework-mcp/src/tools/codebase.ts +6 -6
- package/framework-mcp/src/tools/contract.ts +114 -4
- package/framework-mcp/src/tools/database.ts +1 -1
- package/framework-mcp/src/tools/framework.ts +9 -12
- package/framework-mcp/src/tools/git.ts +2 -2
- package/framework-mcp/src/tools/knowledge.ts +5 -6
- package/framework-mcp/src/tools/memory.ts +5 -6
- package/framework-mcp/src/tools/messages.ts +94 -28
- package/framework-mcp/src/tools/repository.ts +5 -6
- package/framework-mcp/src/tools/scaffold.ts +9 -6
- package/framework-mcp/src/tools/security.ts +4 -4
- package/framework-mcp/src/utils.ts +2 -2
- package/gemini.md +4 -4
- package/package.json +11 -7
- package/panda.config.ts +3 -1
- package/.enderun/benchmarks/.gitkeep +0 -0
- package/.enderun/blueprints/backend/middleware/error-handler.ts +0 -24
- package/.enderun/blueprints/backend/types/api.ts +0 -20
- package/.enderun/blueprints/backend/types/brands.ts +0 -12
- package/.enderun/blueprints/backend/types/constants.ts +0 -34
- package/.enderun/blueprints/backend/types/index.ts +0 -49
- package/.enderun/blueprints/backend/types/logs.ts +0 -16
- package/.enderun/blueprints/backend/types/models.ts +0 -65
- package/.enderun/blueprints/frontend/ui/Button.tsx +0 -60
- package/.enderun/blueprints/frontend/ui/Input.tsx +0 -43
- package/.enderun/monitoring/.gitkeep +0 -0
- package/gemini-extension.json +0 -13
|
@@ -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 { GET_ACADEMY_PERFORMANCE_ARGS_SCHEMA,
|
|
4
|
+
import { GET_ACADEMY_PERFORMANCE_ARGS_SCHEMA, GET_AGENT_AUDIT_REPORT_ARGS_SCHEMA, LOG_AGENT_ACTION_ARGS_SCHEMA } from "../schemas.js";
|
|
5
5
|
export const academyTools = [
|
|
6
6
|
{
|
|
7
7
|
name: "get_academy_performance",
|
|
@@ -101,7 +101,7 @@ export const academyHandlers = {
|
|
|
101
101
|
}).filter(s => s.actions > 0);
|
|
102
102
|
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") }] };
|
|
103
103
|
}
|
|
104
|
-
catch
|
|
104
|
+
catch {
|
|
105
105
|
return { content: [{ type: "text", text: "Failed to generate global performance report." }] };
|
|
106
106
|
}
|
|
107
107
|
},
|
|
@@ -120,13 +120,11 @@ export const academyHandlers = {
|
|
|
120
120
|
const successRate = (successCount / (totalActions || 1)) * 100;
|
|
121
121
|
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.` }] };
|
|
122
122
|
}
|
|
123
|
-
catch
|
|
123
|
+
catch {
|
|
124
124
|
return { content: [{ type: "text", text: "Strategic briefing generation failed." }] };
|
|
125
125
|
}
|
|
126
126
|
},
|
|
127
127
|
generate_academy_progress_report: async (args, projectRoot) => {
|
|
128
|
-
const parsed = GENERATE_ACADEMY_PROGRESS_REPORT_ARGS_SCHEMA.safeParse(args ?? {});
|
|
129
|
-
const days = parsed.success ? parsed.data.days : 7;
|
|
130
128
|
try {
|
|
131
129
|
const frameworkDir = getFrameworkDir(projectRoot);
|
|
132
130
|
const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
|
|
@@ -135,7 +133,7 @@ export const academyHandlers = {
|
|
|
135
133
|
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");
|
|
136
134
|
return { content: [{ type: "text", text: `# 🎓 AGENT ACADEMY PROGRESS REPORT\n\n## 🏆 Key Milestones Achieved\n${milestones}` }] };
|
|
137
135
|
}
|
|
138
|
-
catch
|
|
136
|
+
catch {
|
|
139
137
|
return { content: [{ type: "text", text: "Failed to generate progress report." }] };
|
|
140
138
|
}
|
|
141
139
|
},
|
|
@@ -153,7 +151,7 @@ export const academyHandlers = {
|
|
|
153
151
|
const successCount = logs.filter((l) => l.status === "SUCCESS").length;
|
|
154
152
|
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)}%` }] };
|
|
155
153
|
}
|
|
156
|
-
catch
|
|
154
|
+
catch {
|
|
157
155
|
return { content: [{ type: "text", text: "Failed to generate audit report." }] };
|
|
158
156
|
}
|
|
159
157
|
},
|
|
@@ -177,7 +175,7 @@ export const academyHandlers = {
|
|
|
177
175
|
fs.writeFileSync(logPath, JSON.stringify(logs, null, 2));
|
|
178
176
|
return { content: [{ type: "text", text: `SUCCESS: Logged action to ${parsed.data.agent}.json` }] };
|
|
179
177
|
}
|
|
180
|
-
catch
|
|
178
|
+
catch {
|
|
181
179
|
return { content: [{ type: "text", text: "Failed to log action." }] };
|
|
182
180
|
}
|
|
183
181
|
},
|
|
@@ -135,7 +135,7 @@ export const codebaseHandlers = {
|
|
|
135
135
|
try {
|
|
136
136
|
queryRegex = new RegExp(query, "i");
|
|
137
137
|
}
|
|
138
|
-
catch
|
|
138
|
+
catch {
|
|
139
139
|
return { content: [{ type: "text", text: "Invalid regex pattern in query." }] };
|
|
140
140
|
}
|
|
141
141
|
const matches = [];
|
|
@@ -157,7 +157,7 @@ export const codebaseHandlers = {
|
|
|
157
157
|
}
|
|
158
158
|
return { content: [{ type: "text", text: matches.join("\n") || "No matches found." }] };
|
|
159
159
|
}
|
|
160
|
-
catch
|
|
160
|
+
catch {
|
|
161
161
|
return { content: [{ type: "text", text: "Search failed." }] };
|
|
162
162
|
}
|
|
163
163
|
},
|
|
@@ -223,7 +223,7 @@ export const codebaseHandlers = {
|
|
|
223
223
|
}
|
|
224
224
|
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)"}` }] };
|
|
225
225
|
}
|
|
226
|
-
catch
|
|
226
|
+
catch {
|
|
227
227
|
return { content: [{ type: "text", text: "Intelligence scan failed." }] };
|
|
228
228
|
}
|
|
229
229
|
},
|
|
@@ -253,8 +253,8 @@ export const codebaseHandlers = {
|
|
|
253
253
|
deviations.push("Reference uses 'get' prefix for functions, target does not.");
|
|
254
254
|
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." }] };
|
|
255
255
|
}
|
|
256
|
-
catch
|
|
257
|
-
return { content: [{ type: "text", text: "
|
|
256
|
+
catch {
|
|
257
|
+
return { content: [{ type: "text", text: "Dependency analysis failed." }] };
|
|
258
258
|
}
|
|
259
259
|
},
|
|
260
260
|
generate_dependency_graph: async (args, projectRoot) => {
|
|
@@ -287,7 +287,7 @@ export const codebaseHandlers = {
|
|
|
287
287
|
mermaid += uniqueEdges.join("\n");
|
|
288
288
|
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}` }] };
|
|
289
289
|
}
|
|
290
|
-
catch
|
|
290
|
+
catch {
|
|
291
291
|
return { content: [{ type: "text", text: "Dependency graph generation failed." }] };
|
|
292
292
|
}
|
|
293
293
|
},
|
|
@@ -40,6 +40,23 @@ export const contractTools = [
|
|
|
40
40
|
required: ["domain"],
|
|
41
41
|
},
|
|
42
42
|
},
|
|
43
|
+
{
|
|
44
|
+
name: "validate_frontend_api_contract",
|
|
45
|
+
description: "Scans frontend hooks for API calls and compares them against backend API documentation and contracts. Returns mismatches (missing endpoints, type issues, etc.).",
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: "object",
|
|
48
|
+
properties: {
|
|
49
|
+
frontendHooksPath: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "Relative path to frontend hooks directory (default: apps/web/src/pages)",
|
|
52
|
+
},
|
|
53
|
+
backendApiDocsPath: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Relative path to backend API documentation (default: docs/api)",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
43
60
|
];
|
|
44
61
|
export const contractHandlers = {
|
|
45
62
|
verify_api_contract: async (args, projectRoot) => {
|
|
@@ -52,8 +69,8 @@ export const contractHandlers = {
|
|
|
52
69
|
const storedHash = JSON.parse(fs.readFileSync(contractJsonPath, "utf-8")).contract_hash;
|
|
53
70
|
return { content: [{ type: "text", text: currentHash === storedHash ? "✅ MATCH: Contract is valid and synchronized." : `❌ MISMATCH: Current hash (${currentHash.slice(0, 8)}...) does not match stored hash (${storedHash.slice(0, 8)}...).` }] };
|
|
54
71
|
}
|
|
55
|
-
catch
|
|
56
|
-
return { content: [{ type: "text", text: "
|
|
72
|
+
catch {
|
|
73
|
+
return { content: [{ type: "text", text: "Contract integrity check failed." }] };
|
|
57
74
|
}
|
|
58
75
|
},
|
|
59
76
|
update_contract_hash: async (args, projectRoot) => {
|
|
@@ -72,7 +89,7 @@ export const contractHandlers = {
|
|
|
72
89
|
fs.writeFileSync(contractJsonPath, JSON.stringify(contractJson, null, 2));
|
|
73
90
|
return { content: [{ type: "text", text: `SUCCESS: Contract hash updated to ${currentHash}` }] };
|
|
74
91
|
}
|
|
75
|
-
catch
|
|
92
|
+
catch {
|
|
76
93
|
return { content: [{ type: "text", text: "Failed to update contract hash." }] };
|
|
77
94
|
}
|
|
78
95
|
},
|
|
@@ -100,8 +117,81 @@ export const contractHandlers = {
|
|
|
100
117
|
});
|
|
101
118
|
return { content: [{ type: "text", text: `### CONTRACT INTEGRITY SHIELD: ${parsed.data.domain.toUpperCase()}\n\n` + `- **Missing/Undefined Types:** ${missingTypes.length > 0 ? `⚠️ ${missingTypes.join(", ")}` : "✅ All types synchronized"}\n\n` + `**Result:** ${missingTypes.length === 0 ? "PASSED" : "FAILED"}` }] };
|
|
102
119
|
}
|
|
103
|
-
catch
|
|
120
|
+
catch {
|
|
104
121
|
return { content: [{ type: "text", text: "Contract verification failed." }] };
|
|
105
122
|
}
|
|
106
123
|
},
|
|
124
|
+
validate_frontend_api_contract: async (args, projectRoot) => {
|
|
125
|
+
const a = args;
|
|
126
|
+
const frontendPath = a?.frontendHooksPath || "apps/web/src/pages";
|
|
127
|
+
const backendDocsPath = a?.backendApiDocsPath || "docs/api";
|
|
128
|
+
try {
|
|
129
|
+
const fullFrontendPath = path.join(projectRoot, frontendPath);
|
|
130
|
+
const fullBackendDocsPath = path.join(projectRoot, backendDocsPath);
|
|
131
|
+
if (!fs.existsSync(fullFrontendPath)) {
|
|
132
|
+
return { content: [{ type: "text", text: `Frontend hooks path not found: ${frontendPath}` }] };
|
|
133
|
+
}
|
|
134
|
+
const hookFiles = collectFilesRecursively(fullFrontendPath, new Set(["ts", "tsx"]));
|
|
135
|
+
const apiCalls = [];
|
|
136
|
+
// Hook dosyalarındaki fetch çağrılarını ve response tiplerini çıkar
|
|
137
|
+
for (const file of hookFiles) {
|
|
138
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
139
|
+
// Basit regex ile endpoint + response tipi yakala
|
|
140
|
+
const matches = content.matchAll(/(?:const\s+\w+\s*[:=]\s*await\s+)?fetch\(['"`](\/api\/[^'"`]+)['"`][^)]*\)\s*(?:\.then[^;]+)?(?:\s*as\s+([A-Z][a-zA-Z0-9]+)|:\s*([A-Z][a-zA-Z0-9]+))?/g);
|
|
141
|
+
for (const match of matches) {
|
|
142
|
+
const endpoint = match[1];
|
|
143
|
+
const responseType = match[2] || match[3];
|
|
144
|
+
apiCalls.push({ endpoint, responseType });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const uniqueEndpoints = Array.from(new Set(apiCalls.map(c => c.endpoint)));
|
|
148
|
+
if (!fs.existsSync(fullBackendDocsPath)) {
|
|
149
|
+
return { content: [{ type: "text", text: `Backend API docs path not found: ${backendDocsPath}` }] };
|
|
150
|
+
}
|
|
151
|
+
const backendDocFiles = collectFilesRecursively(fullBackendDocsPath, new Set(["md"]));
|
|
152
|
+
const documentedEndpoints = [];
|
|
153
|
+
for (const file of backendDocFiles) {
|
|
154
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
155
|
+
const matches = content.matchAll(/`?(\/api\/[a-zA-Z0-9/_-]+)`?/g);
|
|
156
|
+
for (const match of matches) {
|
|
157
|
+
documentedEndpoints.push(match[1]);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const missingInDocs = uniqueEndpoints.filter(ep => !documentedEndpoints.some(d => ep.startsWith(d)));
|
|
161
|
+
const missingInHooks = documentedEndpoints.filter(d => !uniqueEndpoints.some(e => e.startsWith(d)));
|
|
162
|
+
let report = `### FRONTEND ↔ BACKEND CONTRACT VALIDATION REPORT\n\n`;
|
|
163
|
+
report += `**Scanned Frontend Hooks:** ${uniqueEndpoints.length} unique endpoints found\n`;
|
|
164
|
+
report += `**Scanned Backend API Docs:** ${documentedEndpoints.length} endpoints documented\n\n`;
|
|
165
|
+
if (missingInDocs.length > 0) {
|
|
166
|
+
report += `⚠️ **Endpoints called from frontend but NOT documented in backend:**\n${missingInDocs.map(e => `- ${e}`).join("\n")}\n\n`;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
report += `✅ All frontend-called endpoints are documented in backend.\n\n`;
|
|
170
|
+
}
|
|
171
|
+
if (missingInHooks.length > 0) {
|
|
172
|
+
report += `ℹ️ **Endpoints documented in backend but NOT used in scanned frontend hooks:**\n${missingInHooks.map(e => `- ${e}`).join("\n")}\n\n`;
|
|
173
|
+
}
|
|
174
|
+
// Basit tip karşılaştırması (eğer responseType varsa)
|
|
175
|
+
const typeMismatches = [];
|
|
176
|
+
for (const call of apiCalls) {
|
|
177
|
+
if (call.responseType) {
|
|
178
|
+
const docContent = backendDocFiles
|
|
179
|
+
.map(f => fs.readFileSync(f, "utf-8"))
|
|
180
|
+
.join("\n");
|
|
181
|
+
if (!docContent.includes(call.responseType)) {
|
|
182
|
+
typeMismatches.push(`${call.endpoint} → expected type "${call.responseType}" not found in docs`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
if (typeMismatches.length > 0) {
|
|
187
|
+
report += `⚠️ **Potential Type Mismatches:**\n${typeMismatches.map(m => `- ${m}`).join("\n")}\n\n`;
|
|
188
|
+
}
|
|
189
|
+
report += `**Result:** ${missingInDocs.length === 0 && typeMismatches.length === 0 ? "PASSED" : "FAILED (see mismatches above)"}`;
|
|
190
|
+
return { content: [{ type: "text", text: report }] };
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
194
|
+
return { content: [{ type: "text", text: `Validation failed: ${message}` }] };
|
|
195
|
+
}
|
|
196
|
+
},
|
|
107
197
|
};
|
|
@@ -45,7 +45,7 @@ export const databaseHandlers = {
|
|
|
45
45
|
return { content: [{ type: "text", text: "No database tables detected." }] };
|
|
46
46
|
return { content: [{ type: "text", text: `### DATABASE SCHEMA MAP\n\n\`\`\`mermaid\n${mermaid}\n\`\`\`\n\n**Total Tables Detected:** ${tablesFound}` }] };
|
|
47
47
|
}
|
|
48
|
-
catch
|
|
48
|
+
catch {
|
|
49
49
|
return { content: [{ type: "text", text: "Database schema analysis failed." }] };
|
|
50
50
|
}
|
|
51
51
|
},
|
|
@@ -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,8 +76,8 @@ 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
|
|
83
|
-
return { content: [{ type: "text", text: "Failed to
|
|
79
|
+
catch {
|
|
80
|
+
return { content: [{ type: "text", text: "Failed to get project gaps." }] };
|
|
84
81
|
}
|
|
85
82
|
},
|
|
86
83
|
get_framework_status: async (args, projectRoot) => {
|
|
@@ -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
|
|
99
|
-
return { content: [{ type: "text", text: "
|
|
95
|
+
catch {
|
|
96
|
+
return { content: [{ type: "text", text: "Failed to get memory insights." }] };
|
|
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
|
|
154
|
-
return { content: [{ type: "text", text: "Failed to
|
|
150
|
+
catch {
|
|
151
|
+
return { content: [{ type: "text", text: "Failed to get framework status." }] };
|
|
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
|
|
168
|
-
return { content: [{ type: "text", text: "
|
|
164
|
+
catch {
|
|
165
|
+
return { content: [{ type: "text", text: "Failed to bootstrap legacy memory." }] };
|
|
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
|
|
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
|
|
79
|
+
catch {
|
|
80
80
|
return { content: [{ type: "text", text: "Knowledge base search failed." }] };
|
|
81
81
|
}
|
|
82
82
|
},
|
|
@@ -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
|
|
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
|
|
130
|
-
return { content: [{ type: "text", text: "Failed to
|
|
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
|
|
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
|
|
79
|
-
|
|
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 read 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
|
|
93
|
-
return { content: [{ type: "text", text: "
|
|
90
|
+
catch {
|
|
91
|
+
return { content: [{ type: "text", text: "Failed to update project memory." }] };
|
|
94
92
|
}
|
|
95
93
|
},
|
|
96
94
|
};
|
|
@@ -73,8 +73,8 @@ export const messageHandlers = {
|
|
|
73
73
|
fs.writeFileSync(messagePath, JSON.stringify(messages, null, 2));
|
|
74
74
|
return { content: [{ type: "text", text: `Hermes: Message sent to @${recipient} [${parsed.data.category} | ${parsed.data.priority}].` }] };
|
|
75
75
|
}
|
|
76
|
-
catch
|
|
77
|
-
return { content: [{ type: "text", text: "Failed to
|
|
76
|
+
catch {
|
|
77
|
+
return { content: [{ type: "text", text: "Failed to get message statistics." }] };
|
|
78
78
|
}
|
|
79
79
|
},
|
|
80
80
|
read_agent_messages: async (args, projectRoot) => {
|
|
@@ -97,8 +97,8 @@ export const messageHandlers = {
|
|
|
97
97
|
const formatted = unread.map((m) => `- [${m.priority}] **${m.from}** (${m.category}): ${m.content} *(Trace: ${m.traceId})*`).join("\n");
|
|
98
98
|
return { content: [{ type: "text", text: `### HERMES INBOX: @${agentName}\n\n${formatted}` }] };
|
|
99
99
|
}
|
|
100
|
-
catch
|
|
101
|
-
return { content: [{ type: "text", text: "Failed to
|
|
100
|
+
catch {
|
|
101
|
+
return { content: [{ type: "text", text: "Failed to send agent message." }] };
|
|
102
102
|
}
|
|
103
103
|
},
|
|
104
104
|
get_agent_inbox_stats: async (args, projectRoot) => {
|
|
@@ -126,8 +126,8 @@ export const messageHandlers = {
|
|
|
126
126
|
}]
|
|
127
127
|
};
|
|
128
128
|
}
|
|
129
|
-
catch
|
|
130
|
-
return { content: [{ type: "text", text: "Failed to
|
|
129
|
+
catch {
|
|
130
|
+
return { content: [{ type: "text", text: "Failed to read agent messages." }] };
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
133
|
};
|
|
@@ -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
|
|
70
|
-
return { content: [{ type: "text", text: "
|
|
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
|
|
98
|
-
return { content: [{ type: "text", text: "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
81
|
-
return { content: [{ type: "text", text: "Security
|
|
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
|
|
134
|
-
return { content: [{ type: "text", text: "
|
|
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.
|
|
3
|
+
export const FRAMEWORK_VERSION = "0.6.1";
|
|
4
4
|
export function getFrameworkDir(projectRoot) {
|
|
5
|
-
const adapters = [".
|
|
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()) {
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
176
|
+
} catch {
|
|
181
177
|
return { content: [{ type: "text", text: "Failed to log action." }] };
|
|
182
178
|
}
|
|
183
179
|
},
|