agent-enderun 0.5.9 → 0.6.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.
Files changed (88) hide show
  1. package/.enderun/PROJECT_MEMORY.md +23 -32
  2. package/.enderun/STATUS.md +19 -10
  3. package/.enderun/agents/analyst.md +10 -4
  4. package/.enderun/agents/backend.md +23 -12
  5. package/.enderun/agents/explorer.md +2 -2
  6. package/.enderun/agents/frontend.md +21 -10
  7. package/.enderun/agents/git.md +1 -1
  8. package/.enderun/agents/manager.md +10 -2
  9. package/.enderun/agents/mobile.md +2 -2
  10. package/.enderun/agents/native.md +2 -2
  11. package/.enderun/blueprints/backend/errors/domain-error.ts +1 -1
  12. package/.enderun/blueprints/backend/types/index.ts +49 -0
  13. package/{packages/shared-types/src → .enderun/blueprints/backend/types}/models.ts +0 -1
  14. package/.enderun/docs/api/README.md +7 -12
  15. package/.enderun/docs/project-docs.md +17 -7
  16. package/.enderun/docs/tech-stack.md +7 -8
  17. package/.enderun/knowledge/blueprint_driven_construction.md +22 -0
  18. package/.enderun/knowledge/code_review_checklist.md +1 -1
  19. package/.enderun/knowledge/contract_versioning.md +5 -5
  20. package/ENDERUN.md +8 -7
  21. package/README.md +51 -35
  22. package/bin/cli.js +217 -29
  23. package/bin/update-contract.js +2 -2
  24. package/{packages/framework-mcp → framework-mcp}/dist/index.js +0 -0
  25. package/{packages/framework-mcp → framework-mcp}/dist/schemas.js +12 -0
  26. package/{packages/framework-mcp → framework-mcp}/dist/tools/contract.js +5 -5
  27. package/{packages/framework-mcp → framework-mcp}/dist/tools/framework.js +3 -2
  28. package/{packages/framework-mcp → framework-mcp}/dist/tools/git.js +2 -4
  29. package/{packages/framework-mcp → framework-mcp}/dist/tools/index.js +3 -0
  30. package/{packages/framework-mcp → framework-mcp}/dist/tools/repository.js +1 -1
  31. package/framework-mcp/dist/tools/scaffold.js +129 -0
  32. package/{packages/framework-mcp → framework-mcp}/dist/utils.js +1 -1
  33. package/{packages/framework-mcp → framework-mcp}/package.json +1 -1
  34. package/{packages/framework-mcp → framework-mcp}/src/schemas.ts +15 -0
  35. package/{packages/framework-mcp → framework-mcp}/src/tools/contract.ts +5 -5
  36. package/{packages/framework-mcp → framework-mcp}/src/tools/framework.ts +3 -2
  37. package/{packages/framework-mcp → framework-mcp}/src/tools/git.ts +2 -3
  38. package/{packages/framework-mcp → framework-mcp}/src/tools/index.ts +3 -0
  39. package/{packages/framework-mcp → framework-mcp}/src/tools/repository.ts +1 -1
  40. package/framework-mcp/src/tools/scaffold.ts +147 -0
  41. package/{packages/framework-mcp → framework-mcp}/src/utils.ts +1 -1
  42. package/gemini-extension.json +1 -1
  43. package/package.json +7 -11
  44. package/.enderun/logs/manager.json +0 -1
  45. package/packages/shared-types/README.md +0 -61
  46. package/packages/shared-types/contract.version.json +0 -12
  47. package/packages/shared-types/dist/api.d.ts +0 -18
  48. package/packages/shared-types/dist/api.js +0 -2
  49. package/packages/shared-types/dist/api.js.map +0 -1
  50. package/packages/shared-types/dist/brands.d.ts +0 -13
  51. package/packages/shared-types/dist/brands.js +0 -2
  52. package/packages/shared-types/dist/brands.js.map +0 -1
  53. package/packages/shared-types/dist/constants.d.ts +0 -27
  54. package/packages/shared-types/dist/constants.js +0 -22
  55. package/packages/shared-types/dist/constants.js.map +0 -1
  56. package/packages/shared-types/dist/index.d.ts +0 -11
  57. package/packages/shared-types/dist/index.js +0 -12
  58. package/packages/shared-types/dist/index.js.map +0 -1
  59. package/packages/shared-types/dist/logs.d.ts +0 -15
  60. package/packages/shared-types/dist/logs.js +0 -2
  61. package/packages/shared-types/dist/logs.js.map +0 -1
  62. package/packages/shared-types/dist/models.d.ts +0 -60
  63. package/packages/shared-types/dist/models.js +0 -2
  64. package/packages/shared-types/dist/models.js.map +0 -1
  65. package/packages/shared-types/package.json +0 -36
  66. package/packages/shared-types/src/index.ts +0 -12
  67. package/packages/shared-types/tsconfig.json +0 -9
  68. /package/{packages/shared-types/src → .enderun/blueprints/backend/types}/api.ts +0 -0
  69. /package/{packages/shared-types/src → .enderun/blueprints/backend/types}/brands.ts +0 -0
  70. /package/{packages/shared-types/src → .enderun/blueprints/backend/types}/constants.ts +0 -0
  71. /package/{packages/shared-types/src → .enderun/blueprints/backend/types}/logs.ts +0 -0
  72. /package/{packages/framework-mcp → framework-mcp}/README.md +0 -0
  73. /package/{packages/framework-mcp → framework-mcp}/dist/tools/academy.js +0 -0
  74. /package/{packages/framework-mcp → framework-mcp}/dist/tools/codebase.js +0 -0
  75. /package/{packages/framework-mcp → framework-mcp}/dist/tools/database.js +0 -0
  76. /package/{packages/framework-mcp → framework-mcp}/dist/tools/knowledge.js +0 -0
  77. /package/{packages/framework-mcp → framework-mcp}/dist/tools/memory.js +0 -0
  78. /package/{packages/framework-mcp → framework-mcp}/dist/tools/messages.js +0 -0
  79. /package/{packages/framework-mcp → framework-mcp}/dist/tools/security.js +0 -0
  80. /package/{packages/framework-mcp → framework-mcp}/src/index.ts +0 -0
  81. /package/{packages/framework-mcp → framework-mcp}/src/tools/academy.ts +0 -0
  82. /package/{packages/framework-mcp → framework-mcp}/src/tools/codebase.ts +0 -0
  83. /package/{packages/framework-mcp → framework-mcp}/src/tools/database.ts +0 -0
  84. /package/{packages/framework-mcp → framework-mcp}/src/tools/knowledge.ts +0 -0
  85. /package/{packages/framework-mcp → framework-mcp}/src/tools/memory.ts +0 -0
  86. /package/{packages/framework-mcp → framework-mcp}/src/tools/messages.ts +0 -0
  87. /package/{packages/framework-mcp → framework-mcp}/src/tools/security.ts +0 -0
  88. /package/{packages/framework-mcp → framework-mcp}/tsconfig.json +0 -0
@@ -27,7 +27,7 @@ export const gitHandlers = {
27
27
  let type = "feat", scope = "code";
28
28
  if (files.some(f => f.includes(".md")))
29
29
  type = "docs";
30
- else if (files.some(f => f.includes("shared-types")))
30
+ else if (files.some(f => f.includes("apps/backend/src/types")))
31
31
  type = "arch";
32
32
  else if (files.some(f => f.includes("framework-mcp")))
33
33
  type = "chore";
@@ -39,9 +39,7 @@ export const gitHandlers = {
39
39
  scope = "web";
40
40
  else if (files.some(f => f.includes("apps/backend")))
41
41
  scope = "backend";
42
- else if (files.some(f => f.includes("packages/shared-types")))
43
- scope = "contract";
44
- else if (files.some(f => f.includes("packages/framework-mcp")))
42
+ else if (files.some(f => f.includes("framework-mcp")))
45
43
  scope = "mcp";
46
44
  const summary = files.length === 1 ? `update ${path.basename(files[0])}` : `update ${files.length} files`;
47
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")}` }] };
@@ -9,6 +9,7 @@ import { gitTools, gitHandlers } from "./git.js";
9
9
  import { databaseTools, databaseHandlers } from "./database.js";
10
10
  import { knowledgeTools, knowledgeHandlers } from "./knowledge.js";
11
11
  import { repositoryTools, repositoryHandlers } from "./repository.js";
12
+ import { scaffoldTools, scaffoldHandlers } from "./scaffold.js";
12
13
  export const allTools = [
13
14
  ...codebaseTools,
14
15
  ...frameworkTools,
@@ -21,6 +22,7 @@ export const allTools = [
21
22
  ...databaseTools,
22
23
  ...knowledgeTools,
23
24
  ...repositoryTools,
25
+ ...scaffoldTools,
24
26
  ];
25
27
  export const allHandlers = {
26
28
  ...codebaseHandlers,
@@ -34,6 +36,7 @@ export const allHandlers = {
34
36
  ...databaseHandlers,
35
37
  ...knowledgeHandlers,
36
38
  ...repositoryHandlers,
39
+ ...scaffoldHandlers,
37
40
  };
38
41
  // Add compatibility aliases
39
42
  allHandlers.codebase_search = allHandlers.search_codebase;
@@ -91,7 +91,7 @@ export const repositoryHandlers = {
91
91
  });
92
92
  });
93
93
  }
94
- const majorDirs = ["apps/backend", "apps/web", "packages/shared-types", "packages/framework-mcp"], missingREADME = majorDirs.filter(dir => fs.existsSync(path.join(projectRoot, dir)) && !fs.existsSync(path.join(projectRoot, dir, "README.md")));
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
97
  catch (error) {
@@ -0,0 +1,129 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { resolveSafePath, getFrameworkDir } from "../utils.js";
4
+ import { INSTANTIATE_BLUEPRINT_ARGS_SCHEMA, LIST_BLUEPRINTS_ARGS_SCHEMA, SAVE_AS_BLUEPRINT_ARGS_SCHEMA } from "../schemas.js";
5
+ export const scaffoldTools = [
6
+ {
7
+ name: "instantiate_blueprint",
8
+ description: "Clones a Gold Standard capability from .enderun/blueprints into the application source.",
9
+ inputSchema: {
10
+ type: "object",
11
+ properties: {
12
+ blueprintPath: { type: "string", description: "Relative path within blueprints/ (e.g., backend/errors)" },
13
+ targetPath: { type: "string", description: "Target directory in the app (e.g., apps/backend/src/errors)" },
14
+ },
15
+ required: ["blueprintPath", "targetPath"],
16
+ },
17
+ },
18
+ {
19
+ name: "save_as_blueprint",
20
+ description: "Saves or updates a high-quality code pattern as a Gold Standard blueprint for reuse.",
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ blueprintPath: { type: "string", description: "Target relative path in blueprints/ (e.g., frontend/ui/Button.tsx)" },
25
+ content: { type: "string", description: "The full source code of the blueprint" },
26
+ description: { type: "string", description: "Brief description of what this blueprint provides" },
27
+ },
28
+ required: ["blueprintPath", "content"],
29
+ },
30
+ },
31
+ {
32
+ name: "list_blueprints",
33
+ description: "Lists all available Gold Standard blueprints in the framework.",
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: {
37
+ category: { type: "string", enum: ["backend", "frontend"], description: "Optional category to filter blueprints" },
38
+ },
39
+ },
40
+ },
41
+ ];
42
+ export const scaffoldHandlers = {
43
+ instantiate_blueprint: async (args, projectRoot) => {
44
+ const parsed = INSTANTIATE_BLUEPRINT_ARGS_SCHEMA.safeParse(args);
45
+ if (!parsed.success)
46
+ return { content: [{ type: "text", text: `Invalid arguments: ${parsed.error.message}` }] };
47
+ const { blueprintPath, targetPath } = parsed.data;
48
+ const frameworkDir = getFrameworkDir(projectRoot);
49
+ const sourceDir = resolveSafePath(projectRoot, path.join(frameworkDir, "blueprints", blueprintPath));
50
+ const destDir = resolveSafePath(projectRoot, targetPath);
51
+ try {
52
+ if (!fs.existsSync(sourceDir)) {
53
+ return { content: [{ type: "text", text: `Blueprint not found: ${blueprintPath}` }] };
54
+ }
55
+ // Create target directory if it doesn't exist
56
+ fs.mkdirSync(path.dirname(destDir), { recursive: true });
57
+ // Copy recursively
58
+ // Using cpSync which is available in Node.js 16.7.0+
59
+ fs.cpSync(sourceDir, destDir, { recursive: true });
60
+ return { content: [{ type: "text", text: `Successfully instantiated blueprint '${blueprintPath}' into '${targetPath}'` }] };
61
+ }
62
+ catch (error) {
63
+ return { content: [{ type: "text", text: `Scaffold failed: ${error.message}` }] };
64
+ }
65
+ },
66
+ save_as_blueprint: async (args, projectRoot) => {
67
+ const parsed = SAVE_AS_BLUEPRINT_ARGS_SCHEMA.safeParse(args);
68
+ if (!parsed.success)
69
+ return { content: [{ type: "text", text: `Invalid arguments: ${parsed.error.message}` }] };
70
+ const { blueprintPath, content, description } = parsed.data;
71
+ const frameworkDir = getFrameworkDir(projectRoot);
72
+ const targetFile = resolveSafePath(projectRoot, path.join(frameworkDir, "blueprints", blueprintPath));
73
+ try {
74
+ // Ensure the blueprints subdirectory exists
75
+ fs.mkdirSync(path.dirname(targetFile), { recursive: true });
76
+ // Write the blueprint content
77
+ fs.writeFileSync(targetFile, content, "utf-8");
78
+ // Optionally write a .metadata file if description provided
79
+ if (description) {
80
+ const metaFile = `${targetFile}.metadata.json`;
81
+ fs.writeFileSync(metaFile, JSON.stringify({ description, savedAt: new Date().toISOString() }, null, 2), "utf-8");
82
+ }
83
+ return { content: [{ type: "text", text: `Successfully saved blueprint to '${blueprintPath}'` }] };
84
+ }
85
+ catch (error) {
86
+ return { content: [{ type: "text", text: `Failed to save blueprint: ${error.message}` }] };
87
+ }
88
+ },
89
+ list_blueprints: async (args, projectRoot) => {
90
+ const parsed = LIST_BLUEPRINTS_ARGS_SCHEMA.safeParse(args ?? {});
91
+ const category = parsed.success ? parsed.data.category : undefined;
92
+ const frameworkDir = getFrameworkDir(projectRoot);
93
+ const blueprintsRoot = path.join(projectRoot, frameworkDir, "blueprints");
94
+ try {
95
+ if (!fs.existsSync(blueprintsRoot)) {
96
+ return { content: [{ type: "text", text: "Blueprints directory not found." }] };
97
+ }
98
+ const walk = (dir) => {
99
+ const results = [];
100
+ if (!fs.existsSync(dir))
101
+ return results;
102
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
103
+ for (const entry of entries) {
104
+ const res = path.join(dir, entry.name);
105
+ if (entry.isDirectory()) {
106
+ // If it's a leaf directory containing files, or we want to show all dirs
107
+ const subEntries = fs.readdirSync(res);
108
+ const hasFiles = subEntries.some(e => !fs.lstatSync(path.join(res, e)).isDirectory());
109
+ if (hasFiles) {
110
+ results.push(path.relative(blueprintsRoot, res));
111
+ }
112
+ results.push(...walk(res));
113
+ }
114
+ }
115
+ return results;
116
+ };
117
+ let available = walk(blueprintsRoot);
118
+ if (category) {
119
+ available = available.filter(b => b.startsWith(category));
120
+ }
121
+ // Remove duplicates
122
+ available = Array.from(new Set(available));
123
+ return { content: [{ type: "text", text: `### AVAILABLE BLUEPRINTS\n\n` + available.map(b => `- ${b}`).join("\n") }] };
124
+ }
125
+ catch (error) {
126
+ return { content: [{ type: "text", text: `Listing blueprints failed: ${error.message}` }] };
127
+ }
128
+ },
129
+ };
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- export const FRAMEWORK_VERSION = "0.5.9";
3
+ export const FRAMEWORK_VERSION = "0.6.1";
4
4
  export function getFrameworkDir(projectRoot) {
5
5
  const adapters = [".gemini", ".claude", ".cursor", ".enderun", ".codex"];
6
6
  for (const adp of adapters) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-enderun-mcp",
3
- "version": "0.5.9",
3
+ "version": "0.6.1",
4
4
  "description": "Enterprise-grade MCP Server for AI Agent Framework",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -124,3 +124,18 @@ export const SYNC_CONTRACT_HASH_ARGS_SCHEMA = z.object({
124
124
  export const VERIFY_FRAMEWORK_HEALTH_ARGS_SCHEMA = z.object({
125
125
  detailed: z.boolean().default(false),
126
126
  });
127
+
128
+ export const INSTANTIATE_BLUEPRINT_ARGS_SCHEMA = z.object({
129
+ blueprintPath: z.string().min(1),
130
+ targetPath: z.string().min(1),
131
+ });
132
+
133
+ export const LIST_BLUEPRINTS_ARGS_SCHEMA = z.object({
134
+ category: z.enum(["backend", "frontend"]).optional(),
135
+ });
136
+
137
+ export const SAVE_AS_BLUEPRINT_ARGS_SCHEMA = z.object({
138
+ blueprintPath: z.string().min(1),
139
+ content: z.string().min(1),
140
+ description: z.string().optional(),
141
+ });
@@ -50,8 +50,8 @@ export const contractTools = [
50
50
  export const contractHandlers = {
51
51
  verify_api_contract: async (args: unknown, projectRoot: string) => {
52
52
  try {
53
- const sharedTypesDir = path.join(projectRoot, "packages/shared-types/src");
54
- const contractJsonPath = path.join(projectRoot, "packages/shared-types/contract.version.json");
53
+ const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
54
+ const contractJsonPath = path.join(projectRoot, "apps/backend/contract.version.json");
55
55
  if (!fs.existsSync(sharedTypesDir) || !fs.existsSync(contractJsonPath)) return { content: [{ type: "text", text: "Missing shared-types directory or contract.version.json" }] };
56
56
  const currentHash = calculateContractHash(sharedTypesDir, projectRoot);
57
57
  const storedHash = JSON.parse(fs.readFileSync(contractJsonPath, "utf-8")).contract_hash;
@@ -62,8 +62,8 @@ export const contractHandlers = {
62
62
  },
63
63
  update_contract_hash: async (args: unknown, projectRoot: string) => {
64
64
  try {
65
- const sharedTypesDir = path.join(projectRoot, "packages/shared-types/src");
66
- const contractJsonPath = path.join(projectRoot, "packages/shared-types/contract.version.json");
65
+ const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
66
+ const contractJsonPath = path.join(projectRoot, "apps/backend/contract.version.json");
67
67
  if (!fs.existsSync(sharedTypesDir)) return { content: [{ type: "text", text: "Missing shared-types directory" }] };
68
68
  const files = collectFilesRecursively(sharedTypesDir, new Set(["ts"])).sort();
69
69
  if (files.length === 0) return { content: [{ type: "text", text: "⚠️ WARNING: No TypeScript files found in shared-types/src. Hash not updated." }] };
@@ -83,7 +83,7 @@ export const contractHandlers = {
83
83
  try {
84
84
  const frameworkDir = getFrameworkDir(projectRoot);
85
85
  const apiDocPath = path.join(projectRoot, frameworkDir, "docs/api", `${parsed.data.domain}.md`);
86
- const sharedTypesDir = path.join(projectRoot, "packages/shared-types/src");
86
+ const sharedTypesDir = path.join(projectRoot, "apps/backend/src/types");
87
87
 
88
88
  if (!fs.existsSync(apiDocPath)) return { content: [{ type: "text", text: `API documentation not found for domain: ${parsed.data.domain}` }] };
89
89
  if (!fs.existsSync(sharedTypesDir)) return { content: [{ type: "text", text: "Shared types directory not found." }] };
@@ -102,8 +102,9 @@ export const frameworkHandlers = {
102
102
  const missing: string[] = [];
103
103
  const frameworkDir = getFrameworkDir(projectRoot);
104
104
  const checkPaths = [
105
- { path: "apps", type: "folder", optional: true },
106
- { path: "packages/shared-types/src", type: "folder" },
105
+ { path: "apps/backend/src/types", type: "folder" },
106
+ { path: "apps/web/src/types", type: "folder" },
107
+ { path: "framework-mcp/src", type: "folder" },
107
108
  { path: path.join(frameworkDir, "docs/api"), type: "folder", optional: true },
108
109
  { path: ".env", type: "file", optional: true },
109
110
  { path: ".env.example", type: "file" },
@@ -26,14 +26,13 @@ export const gitHandlers = {
26
26
  const files = execSync("git diff --staged --name-only", { encoding: "utf-8", cwd: projectRoot }).split("\n").filter(Boolean);
27
27
  let type = "feat", scope = "code";
28
28
  if (files.some(f => f.includes(".md"))) type = "docs";
29
- else if (files.some(f => f.includes("shared-types"))) type = "arch";
29
+ else if (files.some(f => f.includes("apps/backend/src/types"))) type = "arch";
30
30
  else if (files.some(f => f.includes("framework-mcp"))) type = "chore";
31
31
  else if (files.some(f => f.includes("bin/cli.js"))) type = "fix";
32
32
  else if (files.some(f => f.includes("test"))) type = "test";
33
33
  if (files.some(f => f.includes("apps/web"))) scope = "web";
34
34
  else if (files.some(f => f.includes("apps/backend"))) scope = "backend";
35
- else if (files.some(f => f.includes("packages/shared-types"))) scope = "contract";
36
- else if (files.some(f => f.includes("packages/framework-mcp"))) scope = "mcp";
35
+ else if (files.some(f => f.includes("framework-mcp"))) scope = "mcp";
37
36
  const summary = files.length === 1 ? `update ${path.basename(files[0])}` : `update ${files.length} files`;
38
37
  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")}` }] };
39
38
  } catch (error) {
@@ -9,6 +9,7 @@ import { gitTools, gitHandlers } from "./git.js";
9
9
  import { databaseTools, databaseHandlers } from "./database.js";
10
10
  import { knowledgeTools, knowledgeHandlers } from "./knowledge.js";
11
11
  import { repositoryTools, repositoryHandlers } from "./repository.js";
12
+ import { scaffoldTools, scaffoldHandlers } from "./scaffold.js";
12
13
 
13
14
  export const allTools = [
14
15
  ...codebaseTools,
@@ -22,6 +23,7 @@ export const allTools = [
22
23
  ...databaseTools,
23
24
  ...knowledgeTools,
24
25
  ...repositoryTools,
26
+ ...scaffoldTools,
25
27
  ];
26
28
 
27
29
  export const allHandlers: Record<string, (args: unknown, projectRoot: string) => Promise<unknown>> = {
@@ -36,6 +38,7 @@ export const allHandlers: Record<string, (args: unknown, projectRoot: string) =>
36
38
  ...databaseHandlers,
37
39
  ...knowledgeHandlers,
38
40
  ...repositoryHandlers,
41
+ ...scaffoldHandlers,
39
42
  };
40
43
 
41
44
  // Add compatibility aliases
@@ -93,7 +93,7 @@ export const repositoryHandlers = {
93
93
  });
94
94
  });
95
95
  }
96
- const majorDirs = ["apps/backend", "apps/web", "packages/shared-types", "packages/framework-mcp"], missingREADME = majorDirs.filter(dir => fs.existsSync(path.join(projectRoot, dir)) && !fs.existsSync(path.join(projectRoot, dir, "README.md")));
96
+ 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")));
97
97
  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")}` }] };
98
98
  } catch (error) {
99
99
  return { content: [{ type: "text", text: "Documentation debt scan failed." }] };
@@ -0,0 +1,147 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import {
4
+ resolveSafePath,
5
+ getFrameworkDir
6
+ } from "../utils.js";
7
+ import {
8
+ INSTANTIATE_BLUEPRINT_ARGS_SCHEMA,
9
+ LIST_BLUEPRINTS_ARGS_SCHEMA,
10
+ SAVE_AS_BLUEPRINT_ARGS_SCHEMA
11
+ } from "../schemas.js";
12
+
13
+ export const scaffoldTools = [
14
+ {
15
+ name: "instantiate_blueprint",
16
+ description: "Clones a Gold Standard capability from .enderun/blueprints into the application source.",
17
+ inputSchema: {
18
+ type: "object",
19
+ properties: {
20
+ blueprintPath: { type: "string", description: "Relative path within blueprints/ (e.g., backend/errors)" },
21
+ targetPath: { type: "string", description: "Target directory in the app (e.g., apps/backend/src/errors)" },
22
+ },
23
+ required: ["blueprintPath", "targetPath"],
24
+ },
25
+ },
26
+ {
27
+ name: "save_as_blueprint",
28
+ description: "Saves or updates a high-quality code pattern as a Gold Standard blueprint for reuse.",
29
+ inputSchema: {
30
+ type: "object",
31
+ properties: {
32
+ blueprintPath: { type: "string", description: "Target relative path in blueprints/ (e.g., frontend/ui/Button.tsx)" },
33
+ content: { type: "string", description: "The full source code of the blueprint" },
34
+ description: { type: "string", description: "Brief description of what this blueprint provides" },
35
+ },
36
+ required: ["blueprintPath", "content"],
37
+ },
38
+ },
39
+ {
40
+ name: "list_blueprints",
41
+ description: "Lists all available Gold Standard blueprints in the framework.",
42
+ inputSchema: {
43
+ type: "object",
44
+ properties: {
45
+ category: { type: "string", enum: ["backend", "frontend"], description: "Optional category to filter blueprints" },
46
+ },
47
+ },
48
+ },
49
+ ];
50
+
51
+ export const scaffoldHandlers = {
52
+ instantiate_blueprint: async (args: unknown, projectRoot: string) => {
53
+ const parsed = INSTANTIATE_BLUEPRINT_ARGS_SCHEMA.safeParse(args);
54
+ if (!parsed.success) return { content: [{ type: "text", text: `Invalid arguments: ${parsed.error.message}` }] };
55
+
56
+ const { blueprintPath, targetPath } = parsed.data;
57
+ const frameworkDir = getFrameworkDir(projectRoot);
58
+ const sourceDir = resolveSafePath(projectRoot, path.join(frameworkDir, "blueprints", blueprintPath));
59
+ const destDir = resolveSafePath(projectRoot, targetPath);
60
+
61
+ try {
62
+ if (!fs.existsSync(sourceDir)) {
63
+ return { content: [{ type: "text", text: `Blueprint not found: ${blueprintPath}` }] };
64
+ }
65
+
66
+ // Create target directory if it doesn't exist
67
+ fs.mkdirSync(path.dirname(destDir), { recursive: true });
68
+
69
+ // Copy recursively
70
+ // Using cpSync which is available in Node.js 16.7.0+
71
+ fs.cpSync(sourceDir, destDir, { recursive: true });
72
+
73
+ return { content: [{ type: "text", text: `Successfully instantiated blueprint '${blueprintPath}' into '${targetPath}'` }] };
74
+ } catch (error: any) {
75
+ return { content: [{ type: "text", text: `Scaffold failed: ${error.message}` }] };
76
+ }
77
+ },
78
+ save_as_blueprint: async (args: unknown, projectRoot: string) => {
79
+ const parsed = SAVE_AS_BLUEPRINT_ARGS_SCHEMA.safeParse(args);
80
+ if (!parsed.success) return { content: [{ type: "text", text: `Invalid arguments: ${parsed.error.message}` }] };
81
+
82
+ const { blueprintPath, content, description } = parsed.data;
83
+ const frameworkDir = getFrameworkDir(projectRoot);
84
+ const targetFile = resolveSafePath(projectRoot, path.join(frameworkDir, "blueprints", blueprintPath));
85
+
86
+ try {
87
+ // Ensure the blueprints subdirectory exists
88
+ fs.mkdirSync(path.dirname(targetFile), { recursive: true });
89
+
90
+ // Write the blueprint content
91
+ fs.writeFileSync(targetFile, content, "utf-8");
92
+
93
+ // Optionally write a .metadata file if description provided
94
+ if (description) {
95
+ const metaFile = `${targetFile}.metadata.json`;
96
+ fs.writeFileSync(metaFile, JSON.stringify({ description, savedAt: new Date().toISOString() }, null, 2), "utf-8");
97
+ }
98
+
99
+ return { content: [{ type: "text", text: `Successfully saved blueprint to '${blueprintPath}'` }] };
100
+ } catch (error: any) {
101
+ return { content: [{ type: "text", text: `Failed to save blueprint: ${error.message}` }] };
102
+ }
103
+ },
104
+ list_blueprints: async (args: unknown, projectRoot: string) => {
105
+ const parsed = LIST_BLUEPRINTS_ARGS_SCHEMA.safeParse(args ?? {});
106
+ const category = parsed.success ? parsed.data.category : undefined;
107
+ const frameworkDir = getFrameworkDir(projectRoot);
108
+ const blueprintsRoot = path.join(projectRoot, frameworkDir, "blueprints");
109
+
110
+ try {
111
+ if (!fs.existsSync(blueprintsRoot)) {
112
+ return { content: [{ type: "text", text: "Blueprints directory not found." }] };
113
+ }
114
+
115
+ const walk = (dir: string): string[] => {
116
+ const results: string[] = [];
117
+ if (!fs.existsSync(dir)) return results;
118
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
119
+ for (const entry of entries) {
120
+ const res = path.join(dir, entry.name);
121
+ if (entry.isDirectory()) {
122
+ // If it's a leaf directory containing files, or we want to show all dirs
123
+ const subEntries = fs.readdirSync(res);
124
+ const hasFiles = subEntries.some(e => !fs.lstatSync(path.join(res, e)).isDirectory());
125
+ if (hasFiles) {
126
+ results.push(path.relative(blueprintsRoot, res));
127
+ }
128
+ results.push(...walk(res));
129
+ }
130
+ }
131
+ return results;
132
+ };
133
+
134
+ let available = walk(blueprintsRoot);
135
+ if (category) {
136
+ available = available.filter(b => b.startsWith(category));
137
+ }
138
+
139
+ // Remove duplicates
140
+ available = Array.from(new Set(available));
141
+
142
+ return { content: [{ type: "text", text: `### AVAILABLE BLUEPRINTS\n\n` + available.map(b => `- ${b}`).join("\n") }] };
143
+ } catch (error: any) {
144
+ return { content: [{ type: "text", text: `Listing blueprints failed: ${error.message}` }] };
145
+ }
146
+ },
147
+ };
@@ -1,7 +1,7 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
3
 
4
- export const FRAMEWORK_VERSION = "0.5.9";
4
+ export const FRAMEWORK_VERSION = "0.6.1";
5
5
 
6
6
  export function getFrameworkDir(projectRoot: string): string {
7
7
  const adapters = [".gemini", ".claude", ".cursor", ".enderun", ".codex"];
@@ -6,7 +6,7 @@
6
6
  "agent-enderun": {
7
7
  "command": "node",
8
8
  "args": [
9
- "packages/framework-mcp/dist/index.js"
9
+ "framework-mcp/dist/index.js"
10
10
  ]
11
11
  }
12
12
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-enderun",
3
- "version": "0.5.9",
3
+ "version": "0.6.1",
4
4
  "description": "The Supreme AI Governance & Orchestration Framework for Enterprise Development",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -24,21 +24,17 @@
24
24
  "framework"
25
25
  ],
26
26
  "workspaces": [
27
- "packages/*",
28
- "apps/*"
27
+ "apps/*",
28
+ "framework-mcp"
29
29
  ],
30
30
  "bin": {
31
31
  "agent-enderun": "bin/cli.js"
32
32
  },
33
33
  "files": [
34
34
  "bin",
35
- "packages/shared-types/dist",
36
- "packages/shared-types/src",
37
- "packages/shared-types/package.json",
38
- "packages/shared-types/contract.version.json",
39
- "packages/framework-mcp/dist",
40
- "packages/framework-mcp/src",
41
- "packages/framework-mcp/package.json",
35
+ "framework-mcp/dist",
36
+ "framework-mcp/src",
37
+ "framework-mcp/package.json",
42
38
  ".enderun",
43
39
  "ENDERUN.md",
44
40
  "README.md",
@@ -55,7 +51,7 @@
55
51
  "docs"
56
52
  ],
57
53
  "scripts": {
58
- "enderun:build": "npm run build --prefix packages/shared-types && npm run build --prefix packages/framework-mcp",
54
+ "enderun:build": "npm run build --prefix framework-mcp",
59
55
  "enderun:test": "vitest run",
60
56
  "enderun:test:watch": "vitest",
61
57
  "enderun:status": "agent-enderun status",
@@ -1 +0,0 @@
1
- []
@@ -1,61 +0,0 @@
1
- # AI-Enderun Shared Types (v0.3.4)
2
-
3
- English | [Türkçe](#türkçe)
4
-
5
- The `@ai-enderun/shared-types` package is the "Supreme Law" of data within the Agent Enderun framework. It ensures perfect synchronization between backend and frontend through a **Contract-First** approach.
6
-
7
- ## English
8
-
9
- ### Core Principles
10
-
11
- - **Zero Drift:** Backend and frontend implementation must strictly follow these types.
12
- - **Branded Types:** We use the "Branded Types" pattern to ensure type safety for domain identifiers (e.g., `UserID` vs. `ProjectID`).
13
- - **Atomic Versioning:** Every change to this package triggers a hash mismatch in the framework, forcing a contract verification step.
14
-
15
- ### Key Components
16
-
17
- #### Branded Identifiers
18
- Prevents accidental usage of a UserID where a ProjectID is expected.
19
- ```typescript
20
- export type UserID = string & { readonly __brand: "UserID" };
21
- export type ProjectID = string & { readonly __brand: "ProjectID" };
22
- ```
23
-
24
- #### API Contracts
25
- Standardized shapes for requests and responses.
26
- ```typescript
27
- export interface ApiResponse<T> {
28
- data: T;
29
- traceId: string;
30
- timestamp: string;
31
- }
32
- ```
33
-
34
- ### Contract Workflow
35
-
36
- 1. **Modify**: Update `src/index.ts` with new DTOs or Types.
37
- 2. **Build**: `npm run build`
38
- 3. **Verify**: Run `agent-enderun verify-contract` to detect changes.
39
- 4. **Sync**: Update `contract.version.json` with the new hash using the MCP tool `update_contract_hash`.
40
-
41
- ## Türkçe
42
-
43
- `@ai-enderun/shared-types`, Agent Enderun çerçevesindeki verilerin "Yüce Yasası"dır. **Kontrat Öncelikli** (Contract-First) yaklaşımıyla backend ve frontend arasında kusursuz bir uyum sağlar.
44
-
45
- ### Temel Özellikler
46
-
47
- - **Branded Types:** Kimlik karışıklıklarını önlemek için özel tipler kullanılır.
48
- - **API Sözleşmeleri:** Tüm istek ve yanıtlar için standart şablonlar.
49
- - **Hash Doğrulama:** Tip değişiklikleri merkezi bir hash üzerinden takip edilir.
50
-
51
- ### Geliştirme
52
-
53
- ```bash
54
- npm install
55
- npm run build
56
- npm run typecheck
57
- ```
58
-
59
- ## License
60
-
61
- MIT
@@ -1,12 +0,0 @@
1
- {
2
- "version": "0.1.11",
3
- "last_updated": "2026-05-16T16:47:16.000Z",
4
- "contract_hash": "8574144a23e68351f48365f5ccb3d69dc11629af54ec9c1ed0fffd57f967b777",
5
- "breaking_changes": [
6
- {
7
- "version": "0.1.11",
8
- "description": "Extended shared types for Enderun Brain Dashboard"
9
- }
10
- ],
11
- "deprecated_versions": []
12
- }
@@ -1,18 +0,0 @@
1
- import { TraceID } from "./brands.js";
2
- /**
3
- * API Response Wrappers
4
- */
5
- export interface ApiResponse<T> {
6
- data: T;
7
- meta?: {
8
- requestId: TraceID;
9
- timestamp: string;
10
- };
11
- }
12
- export interface ApiError {
13
- error: {
14
- code: string;
15
- message: string;
16
- details?: unknown;
17
- };
18
- }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=api.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":""}
@@ -1,13 +0,0 @@
1
- /**
2
- * Branded Type Utility
3
- */
4
- export type Brand<K, T> = K & {
5
- __brand: T;
6
- };
7
- /**
8
- * Entity IDs (Branded)
9
- */
10
- export type TraceID = Brand<string, "TraceID">;
11
- export type AgentID = Brand<string, "AgentID">;
12
- export type ProjectID = Brand<string, "ProjectID">;
13
- export type UserID = Brand<string, "UserID">;