agent-enderun 0.8.8 → 0.9.1
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/BRAIN_DASHBOARD.md +5 -5
- package/{ENDERUN.md → .enderun/ENDERUN.md} +4 -2
- package/.enderun/PROJECT_MEMORY.md +32 -43
- package/.enderun/STATUS.md +25 -28
- package/.enderun/agents/agent_army_schema.json +29 -7
- package/.enderun/agents/backend.md +48 -39
- package/.enderun/agents/database.md +55 -0
- package/.enderun/agents/devops.md +30 -17
- package/.enderun/agents/explorer.md +5 -5
- package/.enderun/agents/frontend.md +97 -76
- package/.enderun/agents/git.md +4 -4
- package/.enderun/agents/manager.md +68 -59
- package/.enderun/agents/mobile.md +4 -4
- package/.enderun/agents/native.md +106 -0
- package/.enderun/agents/quality.md +122 -0
- package/.enderun/agents/schema/agent-lifecycle-schema.json +29 -8
- package/.enderun/cli-commands.json +7 -3
- package/.enderun/config.json +8 -2
- package/.enderun/knowledge/SHIM_TEMPLATE.md +25 -0
- package/.enderun/knowledge/context_boundary_rules.md +57 -0
- package/.enderun/knowledge/corporate-governance/high-risk-action-approval-flow.md +29 -0
- package/.enderun/knowledge/documentation_ownership.md +53 -0
- package/.enderun/knowledge/eslint-standards.md +63 -0
- package/.enderun/knowledge/frontend_professionalization_guidelines.md +7 -7
- package/.enderun/knowledge/hermes_live_test_guidelines.md +5 -5
- package/.enderun/knowledge/hermes_protocol.md +1 -1
- package/.enderun/knowledge/lessons-learned.md +14 -0
- package/.enderun/knowledge/manager_authority_audit_enforcement.md +10 -10
- package/.enderun/knowledge/project_scaffold_guidelines.md +4 -4
- package/.enderun/knowledge/reference_application_guidelines.md +6 -6
- package/.enderun/mcp_config.json +9 -0
- package/.enderun/memory-graph/agent-contexts/backend.json +1 -1
- package/.enderun/memory-graph/agent-contexts/devops.json +1 -1
- package/.enderun/memory-graph/agent-contexts/explorer.json +1 -1
- package/.enderun/memory-graph/agent-contexts/frontend.json +1 -1
- package/.enderun/memory-graph/agent-contexts/git.json +1 -1
- package/.enderun/memory-graph/agent-contexts/manager.json +1 -1
- package/.enderun/memory-graph/agent-contexts/mobile.json +1 -1
- package/.enderun/memory-graph/agent-contexts/native.json +1 -0
- package/.enderun/memory-graph/agent-contexts/quality.json +1 -0
- package/.enderun/memory-graph/graph.json +123 -15
- package/.enderun/memory-graph/shared-facts.json +26 -31
- package/.enderun/queue/README.md +13 -13
- package/README.md +171 -393
- package/agent.md +25 -0
- package/bin/cli.js +10 -10
- package/bin/init-check.js +69 -0
- package/bin/update-contract.js +57 -38
- package/bin/validate-agent-army.js +38 -13
- package/claude.md +14 -8
- package/docs/README.md +24 -16
- package/docs/architecture/README.md +9 -0
- package/docs/architecture/standards/data-fetching-patterns.md +13 -0
- package/docs/architecture/standards/design-system.md +31 -0
- package/docs/architecture/standards/logging.md +7 -0
- package/docs/architecture/standards/tech-stack.md +9 -0
- package/docs/getting-started.md +9 -259
- package/docs/user/README.md +35 -0
- package/docs/user/action-plan-2026.md +9 -0
- package/docs/user/getting-started.md +13 -0
- package/docs/user/roadmap.md +13 -0
- package/eslint.config.js +68 -0
- package/framework-mcp/dist/index.js +178 -24
- package/framework-mcp/package.json +6 -33
- package/framework-mcp/tsconfig.json +3 -6
- package/gemini.md +12 -6
- package/grok.md +25 -0
- package/package.json +13 -5
- package/panda.config.ts +86 -86
- package/src/cli/adapters.ts +208 -0
- package/src/cli/commands/app.ts +38 -0
- package/src/cli/commands/check.ts +87 -0
- package/src/cli/commands/compliance.ts +55 -0
- package/src/cli/commands/contract.ts +45 -0
- package/src/cli/commands/explorer.ts +45 -0
- package/src/cli/commands/git.ts +39 -0
- package/src/cli/commands/init.ts +272 -0
- package/src/cli/commands/knowledge.ts +44 -0
- package/src/cli/commands/lint.ts +25 -0
- package/src/cli/commands/log.ts +37 -0
- package/src/cli/commands/memory.ts +78 -0
- package/src/cli/commands/orchestrate.ts +111 -0
- package/src/cli/commands/script.ts +20 -0
- package/src/cli/commands/security.ts +38 -0
- package/src/cli/commands/status.ts +59 -0
- package/src/cli/commands/trace.ts +46 -0
- package/src/cli/index.ts +74 -2155
- package/src/cli/utils/app.ts +764 -0
- package/src/cli/utils/claude.ts +56 -0
- package/src/cli/utils/fs.ts +139 -0
- package/src/cli/utils/memory.ts +141 -0
- package/src/cli/utils/pkg.ts +215 -0
- package/src/cli/utils/string.ts +48 -0
- package/src/cli/utils/time.ts +27 -0
- package/tsconfig.json +9 -0
- package/.enderun/agents/analyst.md +0 -238
- package/.enderun/agents/orchestrator.md +0 -172
- package/.enderun/agents/qa.md +0 -124
- package/.enderun/agents/security.md +0 -202
- package/.enderun/knowledge/api_design_rules.md +0 -6
- package/.enderun/knowledge/branded_types_pattern.md +0 -8
- package/.enderun/knowledge/code_review_checklist.md +0 -7
- package/.enderun/knowledge/contract_versioning.md +0 -7
- package/.enderun/knowledge/database_migration.md +0 -6
- package/.enderun/knowledge/deployment_checklist.md +0 -7
- package/.enderun/knowledge/git_commit_strategy.md +0 -10
- package/.enderun/knowledge/monitoring_setup.md +0 -5
- package/.enderun/knowledge/performance_guidelines.md +0 -11
- package/.enderun/knowledge/repository_patterns.md +0 -9
- package/.enderun/knowledge/security_scanning.md +0 -6
- package/.enderun/knowledge/testing_standards.md +0 -7
- package/.enderun/knowledge/troubleshooting_guide.md +0 -5
- package/.enderun/logs/analyst.json +0 -1
- package/.enderun/logs/backend.json +0 -1
- package/.enderun/logs/devops.json +0 -1
- package/.enderun/logs/explorer.json +0 -1
- package/.enderun/logs/frontend.json +0 -1
- package/.enderun/logs/git.json +0 -1
- package/.enderun/logs/manager.json +0 -1
- package/.enderun/logs/mobile.json +0 -1
- package/.enderun/logs/native.json +0 -1
- package/.enderun/logs/orchestrator.json +0 -1
- package/.enderun/logs/qa.json +0 -1
- package/.enderun/logs/security.json +0 -1
- package/.enderun/memory-graph/agent-contexts/analyst.json +0 -1
- package/.enderun/memory-graph/agent-contexts/orchestrator.json +0 -1
- package/.enderun/memory-graph/agent-contexts/qa.json +0 -1
- package/.enderun/memory-graph/agent-contexts/security.json +0 -1
- package/.env.example +0 -10
- package/cursor.md +0 -19
- package/docs/action-plan-2026.md +0 -119
- package/docs/roadmap.md +0 -142
- package/framework-mcp/README.md +0 -55
- package/framework-mcp/dist/schemas.js +0 -84
- package/framework-mcp/dist/tools/codebase.js +0 -294
- package/framework-mcp/dist/tools/contract.js +0 -197
- package/framework-mcp/dist/tools/framework.js +0 -225
- package/framework-mcp/dist/tools/git.js +0 -51
- package/framework-mcp/dist/tools/governance.js +0 -696
- package/framework-mcp/dist/tools/index.js +0 -47
- package/framework-mcp/dist/tools/knowledge.js +0 -133
- package/framework-mcp/dist/tools/memory.js +0 -217
- package/framework-mcp/dist/tools/messages.js +0 -193
- package/framework-mcp/dist/tools/monitoring.js +0 -294
- package/framework-mcp/dist/tools/orchestration.js +0 -369
- package/framework-mcp/dist/tools/pipeline.js +0 -267
- package/framework-mcp/dist/tools/security.js +0 -137
- package/framework-mcp/dist/utils.js +0 -121
- package/framework-mcp/src/index.ts +0 -49
- package/framework-mcp/src/schemas.ts +0 -106
- package/framework-mcp/src/tools/codebase.ts +0 -284
- package/framework-mcp/src/tools/contract.ts +0 -221
- package/framework-mcp/src/tools/framework.ts +0 -223
- package/framework-mcp/src/tools/git.ts +0 -42
- package/framework-mcp/src/tools/governance.ts +0 -891
- package/framework-mcp/src/tools/index.ts +0 -50
- package/framework-mcp/src/tools/knowledge.ts +0 -141
- package/framework-mcp/src/tools/memory.ts +0 -207
- package/framework-mcp/src/tools/messages.ts +0 -213
- package/framework-mcp/src/tools/monitoring.ts +0 -351
- package/framework-mcp/src/tools/orchestration.ts +0 -440
- package/framework-mcp/src/tools/pipeline.ts +0 -353
- package/framework-mcp/src/tools/security.ts +0 -143
- package/framework-mcp/src/utils.ts +0 -130
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import crypto from "crypto";
|
|
4
|
-
import { Project } from "ts-morph";
|
|
5
|
-
import { getFrameworkDir, collectFilesRecursively } from "../utils.js";
|
|
6
|
-
import { VERIFY_CONTRACT_INTEGRITY_ARGS_SCHEMA } from "../schemas.js";
|
|
7
|
-
function calculateContractHash(sharedTypesDir, projectRoot) {
|
|
8
|
-
const files = collectFilesRecursively(sharedTypesDir, new Set(["ts"])).sort();
|
|
9
|
-
const hash = crypto.createHash("sha256");
|
|
10
|
-
files.forEach((filePath) => {
|
|
11
|
-
hash.update(path.relative(projectRoot, filePath));
|
|
12
|
-
hash.update("\0");
|
|
13
|
-
hash.update(fs.readFileSync(filePath));
|
|
14
|
-
hash.update("\0");
|
|
15
|
-
});
|
|
16
|
-
return hash.digest("hex");
|
|
17
|
-
}
|
|
18
|
-
export const contractTools = [
|
|
19
|
-
{
|
|
20
|
-
name: "verify_api_contract",
|
|
21
|
-
description: "Verify if the shared-types match the stored contract hash in contract.version.json.",
|
|
22
|
-
inputSchema: { type: "object", properties: {} },
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
name: "update_contract_hash",
|
|
26
|
-
description: "Generate a new hash for shared-types and update contract.version.json.",
|
|
27
|
-
inputSchema: { type: "object", properties: {} },
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
name: "verify_contract_integrity",
|
|
31
|
-
description: "Deeply analyzes API documentation and shared types to ensure they are perfectly synchronized.",
|
|
32
|
-
inputSchema: {
|
|
33
|
-
type: "object",
|
|
34
|
-
properties: {
|
|
35
|
-
domain: {
|
|
36
|
-
type: "string",
|
|
37
|
-
description: "The API domain to verify (e.g. 'auth', 'user')",
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
required: ["domain"],
|
|
41
|
-
},
|
|
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
|
-
},
|
|
60
|
-
];
|
|
61
|
-
export const contractHandlers = {
|
|
62
|
-
verify_api_contract: async (args, projectRoot) => {
|
|
63
|
-
try {
|
|
64
|
-
const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
|
|
65
|
-
const contractJsonPath = path.join(projectRoot, "apps/backend/contract.version.json");
|
|
66
|
-
if (!fs.existsSync(sharedTypesDir) || !fs.existsSync(contractJsonPath))
|
|
67
|
-
return { content: [{ type: "text", text: "Missing shared-types directory or contract.version.json" }] };
|
|
68
|
-
const currentHash = calculateContractHash(sharedTypesDir, projectRoot);
|
|
69
|
-
const storedHash = JSON.parse(fs.readFileSync(contractJsonPath, "utf-8")).contract_hash;
|
|
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)}...).` }] };
|
|
71
|
-
}
|
|
72
|
-
catch {
|
|
73
|
-
return { content: [{ type: "text", text: "Contract integrity check failed." }] };
|
|
74
|
-
}
|
|
75
|
-
},
|
|
76
|
-
update_contract_hash: async (args, projectRoot) => {
|
|
77
|
-
try {
|
|
78
|
-
const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
|
|
79
|
-
const contractJsonPath = path.join(projectRoot, "apps/backend/contract.version.json");
|
|
80
|
-
if (!fs.existsSync(sharedTypesDir))
|
|
81
|
-
return { content: [{ type: "text", text: "Missing shared-types directory" }] };
|
|
82
|
-
const files = collectFilesRecursively(sharedTypesDir, new Set(["ts"])).sort();
|
|
83
|
-
if (files.length === 0)
|
|
84
|
-
return { content: [{ type: "text", text: "⚠️ WARNING: No TypeScript files found in shared-types/src. Hash not updated." }] };
|
|
85
|
-
const currentHash = calculateContractHash(sharedTypesDir, projectRoot);
|
|
86
|
-
const contractJson = fs.existsSync(contractJsonPath) ? JSON.parse(fs.readFileSync(contractJsonPath, "utf-8")) : {};
|
|
87
|
-
contractJson.contract_hash = currentHash;
|
|
88
|
-
contractJson.last_updated = new Date().toISOString();
|
|
89
|
-
fs.writeFileSync(contractJsonPath, JSON.stringify(contractJson, null, 2));
|
|
90
|
-
return { content: [{ type: "text", text: `SUCCESS: Contract hash updated to ${currentHash}` }] };
|
|
91
|
-
}
|
|
92
|
-
catch {
|
|
93
|
-
return { content: [{ type: "text", text: "Failed to update contract hash." }] };
|
|
94
|
-
}
|
|
95
|
-
},
|
|
96
|
-
verify_contract_integrity: async (args, projectRoot) => {
|
|
97
|
-
const parsed = VERIFY_CONTRACT_INTEGRITY_ARGS_SCHEMA.safeParse(args ?? {});
|
|
98
|
-
if (!parsed.success)
|
|
99
|
-
return { content: [{ type: "text", text: "Invalid domain argument." }] };
|
|
100
|
-
try {
|
|
101
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
102
|
-
const apiDocPath = path.join(projectRoot, frameworkDir, "docs/api", `${parsed.data.domain}.md`);
|
|
103
|
-
const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
|
|
104
|
-
if (!fs.existsSync(apiDocPath))
|
|
105
|
-
return { content: [{ type: "text", text: `API documentation not found for domain: ${parsed.data.domain}` }] };
|
|
106
|
-
if (!fs.existsSync(sharedTypesDir))
|
|
107
|
-
return { content: [{ type: "text", text: "Shared types directory not found." }] };
|
|
108
|
-
const project = new Project();
|
|
109
|
-
project.addSourceFilesAtPaths(path.join(sharedTypesDir, "**/*.ts"));
|
|
110
|
-
const mentionedTypes = Array.from(fs.readFileSync(apiDocPath, "utf-8").matchAll(/`([^`]+)`/g))
|
|
111
|
-
.map(m => m[1])
|
|
112
|
-
.filter(t => /^[A-Z][a-zA-Z0-9]+(DTO|Response|Request|Status|Type)?$/.test(t));
|
|
113
|
-
const uniqueTypes = Array.from(new Set(mentionedTypes));
|
|
114
|
-
const missingTypes = uniqueTypes.filter(t => {
|
|
115
|
-
const found = project.getSourceFiles().some(sf => sf.getInterface(t) || sf.getTypeAlias(t) || sf.getEnum(t) || sf.getClass(t));
|
|
116
|
-
return !found;
|
|
117
|
-
});
|
|
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"}` }] };
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
return { content: [{ type: "text", text: "Contract verification failed." }] };
|
|
122
|
-
}
|
|
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
|
-
},
|
|
197
|
-
};
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
import fs from "fs";
|
|
2
|
-
import path from "path";
|
|
3
|
-
import { getFrameworkDir, collectMarkdownArtifacts, FRAMEWORK_VERSION } from "../utils.js";
|
|
4
|
-
export const frameworkTools = [
|
|
5
|
-
{
|
|
6
|
-
name: "get_framework_status",
|
|
7
|
-
description: "Get the current status of the AI Agent Framework, including active phase and agent states.",
|
|
8
|
-
inputSchema: { type: "object", properties: {} },
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
name: "get_project_gaps",
|
|
12
|
-
description: "Scans the project structure against the defined standards in ENDERUN.md and identifies missing files, folders, or documentation.",
|
|
13
|
-
inputSchema: { type: "object", properties: {} },
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
name: "get_memory_insights",
|
|
17
|
-
description: "Analyze PROJECT_MEMORY.md and BRAIN_DASHBOARD.md to provide insights on what was done, what is being done, and the history.",
|
|
18
|
-
inputSchema: { type: "object", properties: {} },
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "codebase_context",
|
|
22
|
-
description: "Compatibility helper for non-code context discovery. Lists known markdown artifacts under docs/ and memory files.",
|
|
23
|
-
inputSchema: { type: "object", properties: {} },
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
name: "get_system_time",
|
|
27
|
-
description: "Get the current system time in ISO-8601 format (UTC). Use this instead of Shell 'date' commands.",
|
|
28
|
-
inputSchema: { type: "object", properties: {} },
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
name: "bootstrap_legacy_memory",
|
|
32
|
-
description: "Analyzes a pre-existing codebase to automatically generate the initial project memory, learning its tech stack and architecture.",
|
|
33
|
-
inputSchema: { type: "object", properties: {} },
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
name: "verify_framework_health",
|
|
37
|
-
description: "Runs the framework's internal 'check' command and reports system health status via MCP.",
|
|
38
|
-
inputSchema: {
|
|
39
|
-
type: "object",
|
|
40
|
-
properties: {
|
|
41
|
-
detailed: { type: "boolean", default: false, description: "Include detailed issues if any." },
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
];
|
|
46
|
-
export const frameworkHandlers = {
|
|
47
|
-
bootstrap_legacy_memory: async (args, projectRoot) => {
|
|
48
|
-
try {
|
|
49
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
50
|
-
const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
|
|
51
|
-
const pkgPath = path.join(projectRoot, "package.json");
|
|
52
|
-
let techStack = "Unknown";
|
|
53
|
-
if (fs.existsSync(pkgPath)) {
|
|
54
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
55
|
-
const allDeps = Object.keys(pkg.dependencies || {}).concat(Object.keys(pkg.devDependencies || {}));
|
|
56
|
-
const detected = [];
|
|
57
|
-
if (allDeps.includes("react"))
|
|
58
|
-
detected.push("React");
|
|
59
|
-
if (allDeps.includes("next"))
|
|
60
|
-
detected.push("Next.js");
|
|
61
|
-
if (allDeps.includes("typescript"))
|
|
62
|
-
detected.push("TypeScript");
|
|
63
|
-
if (detected.length > 0)
|
|
64
|
-
techStack = detected.join(", ");
|
|
65
|
-
}
|
|
66
|
-
const date = new Date().toISOString().split("T")[0];
|
|
67
|
-
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 |`;
|
|
68
|
-
if (fs.existsSync(memoryPath))
|
|
69
|
-
fs.copyFileSync(memoryPath, memoryPath + ".bak");
|
|
70
|
-
fs.writeFileSync(memoryPath, bootstrapContent);
|
|
71
|
-
return { content: [{ type: "text", text: `Legacy Codebase Bootstrap complete. Detected Stack: ${techStack}.` }] };
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
return { content: [{ type: "text", text: "Failed to bootstrap legacy memory." }] };
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
get_framework_status: async (args, projectRoot) => {
|
|
78
|
-
try {
|
|
79
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
80
|
-
const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
|
|
81
|
-
const memoryContent = fs.readFileSync(memoryPath, "utf-8");
|
|
82
|
-
const statusRowMatch = memoryContent.match(/\| Active Phase \| Profile \| Last Update \| Active Trace ID \| Blockers \|\n\| :----------- \| :------ \| :---------- \| :-------------- \| :------- \|\n\| ([^|]+) \| ([^|]+) \| ([^|]+) \| ([^|]+) \| ([^|]+) \|/);
|
|
83
|
-
const phase = statusRowMatch?.[1]?.trim() ?? "UNKNOWN";
|
|
84
|
-
const profile = statusRowMatch?.[2]?.trim() ?? "UNKNOWN";
|
|
85
|
-
return {
|
|
86
|
-
content: [{ type: "text", text: `Framework active (v${FRAMEWORK_VERSION}). Phase: ${phase}. Profile: ${profile}.` }],
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return { content: [{ type: "text", text: "Failed to get framework status." }] };
|
|
91
|
-
}
|
|
92
|
-
},
|
|
93
|
-
get_project_gaps: async (args, projectRoot) => {
|
|
94
|
-
const missing = [];
|
|
95
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
96
|
-
const checkPaths = [
|
|
97
|
-
{ path: "apps/backend/src/types", type: "folder", optional: true },
|
|
98
|
-
{ path: "apps/web/src/types", type: "folder", optional: true },
|
|
99
|
-
{ path: "framework-mcp/src", type: "folder" },
|
|
100
|
-
{ path: ".env", type: "file", optional: true },
|
|
101
|
-
{ path: ".env.example", type: "file" },
|
|
102
|
-
{ path: path.join(frameworkDir, "PROJECT_MEMORY.md"), type: "file" },
|
|
103
|
-
{ path: path.join(frameworkDir, "BRAIN_DASHBOARD.md"), type: "file" },
|
|
104
|
-
{ path: "docs/README.md", type: "file" },
|
|
105
|
-
{ path: "docs/getting-started.md", type: "file" },
|
|
106
|
-
{ path: "docs/architecture/approval-flows.md", type: "file", optional: true },
|
|
107
|
-
{ path: "docs/backend/error-handling.md", type: "file", optional: true },
|
|
108
|
-
{ path: "docs/frontend/component-patterns.md", type: "file", optional: true },
|
|
109
|
-
];
|
|
110
|
-
for (const item of checkPaths) {
|
|
111
|
-
const fullPath = path.join(projectRoot, item.path);
|
|
112
|
-
if (!fs.existsSync(fullPath) && !item.optional) {
|
|
113
|
-
missing.push(`[MISSING ${item.type.toUpperCase()}] ${item.path}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
const agentsDir = path.join(projectRoot, frameworkDir, "agents");
|
|
117
|
-
if (!fs.existsSync(agentsDir)) {
|
|
118
|
-
missing.push(`[MISSING FOLDER] ${frameworkDir}/agents`);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
const agents = fs.readdirSync(agentsDir)
|
|
122
|
-
.filter((f) => f.endsWith(".md") && f !== "README.md")
|
|
123
|
-
.map((f) => f.replace(".md", ""));
|
|
124
|
-
const logsDir = path.join(projectRoot, frameworkDir, "logs");
|
|
125
|
-
for (const agentName of agents) {
|
|
126
|
-
const logFile = path.join(logsDir, `${agentName}.json`);
|
|
127
|
-
if (!fs.existsSync(logFile)) {
|
|
128
|
-
missing.push(`[MISSING LOG FILE] ${frameworkDir}/logs/${agentName}.json (Expected for agent ${agentName})`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
// v1.0 Army infrastructure checks
|
|
132
|
-
const v1Dirs = [
|
|
133
|
-
path.join(projectRoot, frameworkDir, "memory-graph"),
|
|
134
|
-
path.join(projectRoot, frameworkDir, "memory-graph", "agent-contexts"),
|
|
135
|
-
path.join(projectRoot, frameworkDir, "queue"),
|
|
136
|
-
path.join(projectRoot, frameworkDir, "agents", "schema"),
|
|
137
|
-
];
|
|
138
|
-
for (const d of v1Dirs) {
|
|
139
|
-
if (!fs.existsSync(d)) {
|
|
140
|
-
missing.push(`[MISSING v1.0 DIR] ${path.relative(projectRoot, d)}`);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return { content: [{ type: "text", text: missing.length > 0 ? `Detected Gaps:\n${missing.join("\n")}` : "No structural gaps detected based on core standards." }] };
|
|
145
|
-
},
|
|
146
|
-
get_memory_insights: async (args, projectRoot) => {
|
|
147
|
-
try {
|
|
148
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
149
|
-
const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
|
|
150
|
-
const dashboardPath = path.join(projectRoot, frameworkDir, "BRAIN_DASHBOARD.md");
|
|
151
|
-
const memory = fs.existsSync(memoryPath) ? fs.readFileSync(memoryPath, "utf-8") : "Memory file missing.";
|
|
152
|
-
const dashboard = fs.existsSync(dashboardPath) ? fs.readFileSync(dashboardPath, "utf-8") : "Dashboard file missing.";
|
|
153
|
-
const history = memory.split("## HISTORY")[1] || "No history found.";
|
|
154
|
-
const activeTasks = memory.split("## ACTIVE TASKS")[1]?.split("##")[0] || "No active tasks.";
|
|
155
|
-
const dashboardAgents = dashboard.split("## 📈 Visualizations")[0] || dashboard;
|
|
156
|
-
return {
|
|
157
|
-
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)}...` }],
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
catch {
|
|
161
|
-
return { content: [{ type: "text", text: "Failed to get memory insights." }] };
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
codebase_context: async (args, projectRoot) => {
|
|
165
|
-
try {
|
|
166
|
-
const artifacts = collectMarkdownArtifacts(projectRoot);
|
|
167
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
168
|
-
const memoryPath = path.join(projectRoot, frameworkDir, "PROJECT_MEMORY.md");
|
|
169
|
-
const dashboardPath = path.join(projectRoot, frameworkDir, "BRAIN_DASHBOARD.md");
|
|
170
|
-
return {
|
|
171
|
-
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."}` }],
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
catch {
|
|
175
|
-
return { content: [{ type: "text", text: "Failed to gather codebase context." }] };
|
|
176
|
-
}
|
|
177
|
-
},
|
|
178
|
-
get_system_time: async () => {
|
|
179
|
-
return { content: [{ type: "text", text: new Date().toISOString() }] };
|
|
180
|
-
},
|
|
181
|
-
verify_framework_health: async (args, projectRoot) => {
|
|
182
|
-
try {
|
|
183
|
-
const frameworkDir = getFrameworkDir(projectRoot);
|
|
184
|
-
const requiredFiles = [
|
|
185
|
-
["Constitution", fs.existsSync(path.join(projectRoot, "ENDERUN.md")) ? "ENDERUN.md" : path.join(frameworkDir, "ENDERUN.md")],
|
|
186
|
-
["Memory", path.join(frameworkDir, "PROJECT_MEMORY.md")],
|
|
187
|
-
["Command Map", path.join(frameworkDir, "cli-commands.json")],
|
|
188
|
-
["Framework Config", path.join(frameworkDir, "config.json")],
|
|
189
|
-
["Agent Status", path.join(frameworkDir, "STATUS.md")],
|
|
190
|
-
["MCP Config", "mcp.json"],
|
|
191
|
-
["Backend Contract", "apps/backend/contract.version.json"],
|
|
192
|
-
["MCP Server", "framework-mcp/package.json"],
|
|
193
|
-
["Panda CSS Config", "panda.config.ts"],
|
|
194
|
-
["Brain Dashboard", path.join(frameworkDir, "BRAIN_DASHBOARD.md")],
|
|
195
|
-
["Docs Portal", "docs/README.md"],
|
|
196
|
-
["Getting Started", "docs/getting-started.md"],
|
|
197
|
-
];
|
|
198
|
-
const lines = [];
|
|
199
|
-
let issues = 0;
|
|
200
|
-
for (const [name, relativePath] of requiredFiles) {
|
|
201
|
-
if (fs.existsSync(path.join(projectRoot, relativePath))) {
|
|
202
|
-
lines.push(`OK ${name}: ${relativePath}`);
|
|
203
|
-
}
|
|
204
|
-
else {
|
|
205
|
-
issues += 1;
|
|
206
|
-
lines.push(`MISSING ${name}: ${relativePath}`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
const buildPath = path.join(projectRoot, "framework-mcp/dist/index.js");
|
|
210
|
-
if (fs.existsSync(buildPath)) {
|
|
211
|
-
lines.push("OK MCP Build: framework-mcp/dist/index.js");
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
issues += 1;
|
|
215
|
-
lines.push("MISSING MCP Build: framework-mcp/dist/index.js");
|
|
216
|
-
}
|
|
217
|
-
const status = issues === 0 ? "PASSED" : "FAILED";
|
|
218
|
-
return { content: [{ type: "text", text: `### FRAMEWORK HEALTH CHECK (${status})\n\n${lines.join("\n")}` }] };
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
const err = error;
|
|
222
|
-
return { content: [{ type: "text", text: `### FRAMEWORK HEALTH CHECK (FAILED)\n\n${err.message ?? "Unknown error"}` }] };
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
};
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import path from "path";
|
|
2
|
-
import { execSync } from "child_process";
|
|
3
|
-
import { GENERATE_SEMANTIC_COMMIT_MESSAGE_ARGS_SCHEMA } from "../schemas.js";
|
|
4
|
-
export const gitTools = [
|
|
5
|
-
{
|
|
6
|
-
name: "generate_semantic_commit_message",
|
|
7
|
-
description: "Analyzes staged git changes and generates a structured semantic commit message based on project standards.",
|
|
8
|
-
inputSchema: {
|
|
9
|
-
type: "object",
|
|
10
|
-
properties: {
|
|
11
|
-
traceId: { type: "string", description: "The active Trace ID (ULID)" },
|
|
12
|
-
},
|
|
13
|
-
required: ["traceId"],
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
];
|
|
17
|
-
export const gitHandlers = {
|
|
18
|
-
generate_semantic_commit_message: async (args, projectRoot) => {
|
|
19
|
-
const parsed = GENERATE_SEMANTIC_COMMIT_MESSAGE_ARGS_SCHEMA.safeParse(args ?? {});
|
|
20
|
-
if (!parsed.success)
|
|
21
|
-
return { content: [{ type: "text", text: "Invalid traceId argument." }] };
|
|
22
|
-
try {
|
|
23
|
-
const diff = execSync("git diff --staged", { encoding: "utf-8", cwd: projectRoot });
|
|
24
|
-
if (!diff)
|
|
25
|
-
return { content: [{ type: "text", text: "No staged changes found." }] };
|
|
26
|
-
const files = execSync("git diff --staged --name-only", { encoding: "utf-8", cwd: projectRoot }).split("\n").filter(Boolean);
|
|
27
|
-
let type = "feat", scope = "code";
|
|
28
|
-
if (files.some(f => f.includes(".md")))
|
|
29
|
-
type = "docs";
|
|
30
|
-
else if (files.some(f => f.includes("apps/backend/src/types")))
|
|
31
|
-
type = "arch";
|
|
32
|
-
else if (files.some(f => f.includes("framework-mcp")))
|
|
33
|
-
type = "chore";
|
|
34
|
-
else if (files.some(f => f.includes("bin/cli.js")))
|
|
35
|
-
type = "fix";
|
|
36
|
-
else if (files.some(f => f.includes("test")))
|
|
37
|
-
type = "test";
|
|
38
|
-
if (files.some(f => f.includes("apps/web")))
|
|
39
|
-
scope = "web";
|
|
40
|
-
else if (files.some(f => f.includes("apps/backend")))
|
|
41
|
-
scope = "backend";
|
|
42
|
-
else if (files.some(f => f.includes("framework-mcp")))
|
|
43
|
-
scope = "mcp";
|
|
44
|
-
const summary = files.length === 1 ? `update ${path.basename(files[0])}` : `update ${files.length} files`;
|
|
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
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
return { content: [{ type: "text", text: "Failed to generate semantic commit message." }] };
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
};
|