agent-enderun 1.10.4 → 1.11.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 (210) hide show
  1. package/README.md +34 -45
  2. package/dist/framework-mcp/tests/tools/quality/check_lint.test.js +1 -1
  3. package/dist/framework-mcp/tests/tools/quality/check_lint.test.js.map +1 -1
  4. package/dist/src/cli/adapters/core.d.ts +1 -1
  5. package/dist/src/cli/adapters/core.js +0 -1
  6. package/dist/src/cli/adapters/core.js.map +1 -1
  7. package/dist/src/cli/adapters/index.d.ts +1 -0
  8. package/dist/src/cli/adapters/index.js +1 -0
  9. package/dist/src/cli/adapters/index.js.map +1 -1
  10. package/dist/src/cli/adapters/scaffold.d.ts +1 -1
  11. package/dist/src/cli/adapters/scaffold.js +13 -7
  12. package/dist/src/cli/adapters/scaffold.js.map +1 -1
  13. package/dist/src/cli/commands/init/scaffold-core.d.ts +5 -2
  14. package/dist/src/cli/commands/init/scaffold-core.js +28 -6
  15. package/dist/src/cli/commands/init/scaffold-core.js.map +1 -1
  16. package/dist/src/cli/commands/init.js +31 -4
  17. package/dist/src/cli/commands/init.js.map +1 -1
  18. package/dist/src/cli/commands/orchestrate.d.ts +9 -7
  19. package/dist/src/cli/commands/orchestrate.js +40 -4
  20. package/dist/src/cli/commands/orchestrate.js.map +1 -1
  21. package/dist/src/cli/commands/plan.d.ts +3 -1
  22. package/dist/src/cli/commands/plan.js +79 -22
  23. package/dist/src/cli/commands/plan.js.map +1 -1
  24. package/dist/src/cli/index.js +11 -15
  25. package/dist/src/cli/index.js.map +1 -1
  26. package/dist/src/cli/utils/compliance.js +0 -1
  27. package/dist/src/cli/utils/compliance.js.map +1 -1
  28. package/dist/src/cli/utils/config-schema.d.ts +7 -7
  29. package/dist/src/cli/utils/pkg.d.ts +19 -0
  30. package/dist/src/cli/utils/pkg.js +29 -5
  31. package/dist/src/cli/utils/pkg.js.map +1 -1
  32. package/dist/src/modules/adapters/definitions.js +1 -1
  33. package/dist/src/modules/adapters/definitions.js.map +1 -1
  34. package/dist/src/modules/adapters/shared.js +7 -4
  35. package/dist/src/modules/adapters/shared.js.map +1 -1
  36. package/dist/src/modules/agents/definitions.d.ts +1 -1
  37. package/dist/src/modules/agents/definitions.js +129 -69
  38. package/dist/src/modules/agents/definitions.js.map +1 -1
  39. package/dist/src/modules/agents/registry/analyst.js +5 -1
  40. package/dist/src/modules/agents/registry/analyst.js.map +1 -1
  41. package/dist/src/modules/agents/registry/backend.js +5 -4
  42. package/dist/src/modules/agents/registry/backend.js.map +1 -1
  43. package/dist/src/modules/agents/registry/database.js +2 -1
  44. package/dist/src/modules/agents/registry/database.js.map +1 -1
  45. package/dist/src/modules/agents/registry/devops.js +2 -0
  46. package/dist/src/modules/agents/registry/devops.js.map +1 -1
  47. package/dist/src/modules/agents/registry/explorer.js +1 -0
  48. package/dist/src/modules/agents/registry/explorer.js.map +1 -1
  49. package/dist/src/modules/agents/registry/git.js +3 -1
  50. package/dist/src/modules/agents/registry/git.js.map +1 -1
  51. package/dist/src/modules/agents/registry/manager.js +8 -2
  52. package/dist/src/modules/agents/registry/manager.js.map +1 -1
  53. package/dist/src/modules/agents/registry/native.js +5 -1
  54. package/dist/src/modules/agents/registry/native.js.map +1 -1
  55. package/dist/src/modules/agents/registry/security.js +1 -0
  56. package/dist/src/modules/agents/registry/security.js.map +1 -1
  57. package/dist/src/shared/constants.d.ts +1 -1
  58. package/dist/src/shared/constants.js +10 -9
  59. package/dist/src/shared/constants.js.map +1 -1
  60. package/dist/tests/approve.test.js +4 -9
  61. package/dist/tests/approve.test.js.map +1 -1
  62. package/dist/tests/integration/agent_flow.test.js +2 -2
  63. package/dist/tests/integration/agent_flow.test.js.map +1 -1
  64. package/dist/tests/orchestrate.test.js +2 -7
  65. package/dist/tests/orchestrate.test.js.map +1 -1
  66. package/framework-mcp/dist/constants.js +64 -0
  67. package/framework-mcp/dist/index.js +109 -0
  68. package/framework-mcp/dist/tools/control_plane/locking.js +64 -0
  69. package/framework-mcp/dist/tools/control_plane/registry.js +34 -0
  70. package/framework-mcp/dist/tools/dashboard/start_dashboard.js +29 -0
  71. package/framework-mcp/dist/tools/definitions.js +300 -0
  72. package/framework-mcp/dist/tools/file_system/batch_surgical_edit.js +59 -0
  73. package/framework-mcp/dist/tools/file_system/patch_file.js +25 -0
  74. package/framework-mcp/dist/tools/file_system/read_file.js +51 -0
  75. package/framework-mcp/dist/tools/file_system/replace_text.js +43 -0
  76. package/framework-mcp/dist/tools/file_system/write_file.js +38 -0
  77. package/framework-mcp/dist/tools/framework/audit_deps.js +41 -0
  78. package/framework-mcp/dist/tools/framework/get_status.js +5 -0
  79. package/framework-mcp/dist/tools/framework/orchestrate.js +5 -0
  80. package/framework-mcp/dist/tools/framework/run_tests.js +25 -0
  81. package/framework-mcp/dist/tools/framework/update_contract_hash.js +5 -0
  82. package/framework-mcp/dist/tools/framework/update_memory.js +8 -0
  83. package/framework-mcp/dist/tools/index.js +62 -0
  84. package/framework-mcp/dist/tools/memory/get_insights.js +34 -0
  85. package/framework-mcp/dist/tools/memory/read_memory.js +28 -0
  86. package/framework-mcp/dist/tools/messaging/log_action.js +22 -0
  87. package/framework-mcp/dist/tools/messaging/send_message.js +87 -0
  88. package/framework-mcp/dist/tools/observability/check_ports.js +26 -0
  89. package/framework-mcp/dist/tools/observability/get_health.js +19 -0
  90. package/framework-mcp/dist/tools/quality/check_lint.js +28 -0
  91. package/framework-mcp/dist/tools/search/get_gaps.js +48 -0
  92. package/framework-mcp/dist/tools/search/get_map.js +43 -0
  93. package/framework-mcp/dist/tools/search/grep_search.js +76 -0
  94. package/framework-mcp/dist/tools/search/list_dir.js +28 -0
  95. package/framework-mcp/dist/tools/shell/run_command.js +46 -0
  96. package/framework-mcp/dist/tools/types.js +1 -0
  97. package/framework-mcp/dist/utils/cli.js +20 -0
  98. package/framework-mcp/dist/utils/compliance.js +29 -0
  99. package/framework-mcp/dist/utils/fs.js +44 -0
  100. package/framework-mcp/dist/utils/metrics.js +56 -0
  101. package/framework-mcp/dist/utils/security.js +60 -0
  102. package/framework-mcp/package.json +19 -0
  103. package/framework-mcp/src/constants.ts +78 -0
  104. package/framework-mcp/src/declarations.d.ts +17 -0
  105. package/framework-mcp/src/index.ts +132 -0
  106. package/framework-mcp/src/tools/control_plane/locking.ts +71 -0
  107. package/framework-mcp/src/tools/control_plane/registry.ts +38 -0
  108. package/framework-mcp/src/tools/dashboard/start_dashboard.ts +33 -0
  109. package/framework-mcp/src/tools/definitions.ts +302 -0
  110. package/framework-mcp/src/tools/file_system/batch_surgical_edit.ts +79 -0
  111. package/framework-mcp/src/tools/file_system/patch_file.ts +33 -0
  112. package/framework-mcp/src/tools/file_system/read_file.ts +58 -0
  113. package/framework-mcp/src/tools/file_system/replace_text.ts +52 -0
  114. package/framework-mcp/src/tools/file_system/write_file.ts +45 -0
  115. package/framework-mcp/src/tools/framework/audit_deps.ts +49 -0
  116. package/framework-mcp/src/tools/framework/get_status.ts +7 -0
  117. package/framework-mcp/src/tools/framework/orchestrate.ts +7 -0
  118. package/framework-mcp/src/tools/framework/run_tests.ts +28 -0
  119. package/framework-mcp/src/tools/framework/update_contract_hash.ts +7 -0
  120. package/framework-mcp/src/tools/framework/update_memory.ts +10 -0
  121. package/framework-mcp/src/tools/index.ts +66 -0
  122. package/framework-mcp/src/tools/memory/get_insights.ts +41 -0
  123. package/framework-mcp/src/tools/memory/read_memory.ts +31 -0
  124. package/framework-mcp/src/tools/messaging/log_action.ts +28 -0
  125. package/framework-mcp/src/tools/messaging/send_message.ts +89 -0
  126. package/framework-mcp/src/tools/observability/check_ports.ts +30 -0
  127. package/framework-mcp/src/tools/observability/get_health.ts +24 -0
  128. package/framework-mcp/src/tools/quality/check_lint.ts +33 -0
  129. package/framework-mcp/src/tools/search/get_gaps.ts +54 -0
  130. package/framework-mcp/src/tools/search/get_map.ts +48 -0
  131. package/framework-mcp/src/tools/search/grep_search.ts +76 -0
  132. package/framework-mcp/src/tools/search/list_dir.ts +34 -0
  133. package/framework-mcp/src/tools/shell/run_command.ts +56 -0
  134. package/framework-mcp/src/tools/types.ts +89 -0
  135. package/framework-mcp/src/utils/cli.ts +20 -0
  136. package/framework-mcp/src/utils/compliance.ts +37 -0
  137. package/framework-mcp/src/utils/fs.ts +45 -0
  138. package/framework-mcp/src/utils/metrics.ts +73 -0
  139. package/framework-mcp/src/utils/security.ts +66 -0
  140. package/framework-mcp/tests/tools/file_system/file_system_tools.test.ts +212 -0
  141. package/framework-mcp/tests/tools/messaging/send_message.test.ts +136 -0
  142. package/framework-mcp/tests/tools/quality/check_lint.test.ts +46 -0
  143. package/framework-mcp/tests/tools/shell/run_command.test.ts +55 -0
  144. package/framework-mcp/tsconfig.json +14 -0
  145. package/package.json +5 -3
  146. package/src/cli/adapters/core.ts +2 -3
  147. package/src/cli/adapters/index.ts +1 -0
  148. package/src/cli/adapters/scaffold.ts +20 -7
  149. package/src/cli/commands/init/scaffold-core.ts +45 -6
  150. package/src/cli/commands/init.ts +31 -2
  151. package/src/cli/commands/orchestrate.ts +41 -4
  152. package/src/cli/commands/plan.ts +89 -23
  153. package/src/cli/index.ts +14 -19
  154. package/src/cli/utils/compliance.ts +8 -9
  155. package/src/cli/utils/pkg.ts +42 -13
  156. package/src/modules/adapters/definitions.ts +1 -1
  157. package/src/modules/adapters/shared.ts +7 -4
  158. package/src/modules/agents/definitions.ts +140 -73
  159. package/src/modules/agents/registry/analyst.ts +5 -1
  160. package/src/modules/agents/registry/backend.ts +5 -4
  161. package/src/modules/agents/registry/database.ts +2 -1
  162. package/src/modules/agents/registry/devops.ts +2 -0
  163. package/src/modules/agents/registry/explorer.ts +1 -0
  164. package/src/modules/agents/registry/git.ts +3 -1
  165. package/src/modules/agents/registry/manager.ts +8 -2
  166. package/src/modules/agents/registry/native.ts +5 -1
  167. package/src/modules/agents/registry/security.ts +1 -0
  168. package/src/shared/constants.ts +14 -13
  169. package/templates/prompts/bug-fix-recipe.md +20 -0
  170. package/templates/prompts/contract-design-recipe.md +21 -0
  171. package/templates/prompts/db-management-recipe.md +25 -0
  172. package/templates/prompts/deployment-recipe.md +23 -0
  173. package/templates/prompts/new-feature-recipe.md +19 -0
  174. package/templates/prompts/performance-optimization-recipe.md +23 -0
  175. package/templates/prompts/pull-request-template.md +21 -0
  176. package/templates/prompts/refactoring-recipe.md +21 -0
  177. package/templates/prompts/security-audit-recipe.md +20 -0
  178. package/templates/standards/architecture-standards.md +23 -0
  179. package/templates/standards/auth-standards.md +125 -0
  180. package/templates/standards/crud-governance.md +21 -0
  181. package/templates/standards/deployment-standards.md +21 -0
  182. package/templates/standards/frontend-standards.md +37 -0
  183. package/templates/standards/github-actions-standards.md +43 -0
  184. package/templates/standards/i18n-standards.md +17 -0
  185. package/templates/standards/kysely-standards.md +47 -0
  186. package/templates/standards/llm-governance.md +15 -0
  187. package/templates/standards/logging-and-secrets.md +34 -0
  188. package/templates/standards/mobile-standards.md +23 -0
  189. package/templates/standards/observability-standards.md +15 -0
  190. package/templates/standards/performance-standards.md +15 -0
  191. package/templates/standards/pino-standards.md +46 -0
  192. package/templates/standards/playwright-standards.md +54 -0
  193. package/templates/standards/quality-standards.md +31 -0
  194. package/templates/standards/react-query-standards.md +72 -0
  195. package/templates/standards/react-router-standards.md +62 -0
  196. package/templates/standards/security-audit-standards.md +16 -0
  197. package/templates/standards/security-standards.md +21 -0
  198. package/templates/standards/swagger-standards.md +50 -0
  199. package/templates/standards/tailwind-standards.md +20 -0
  200. package/templates/standards/testing-standards.md +31 -0
  201. package/templates/standards/typeorm-standards.md +49 -0
  202. package/templates/standards/vitest-standards.md +110 -0
  203. package/src/cli/commands/app.ts +0 -56
  204. package/src/cli/utils/app-backend.ts +0 -257
  205. package/src/cli/utils/app-docs.ts +0 -83
  206. package/src/cli/utils/app-frontend.ts +0 -263
  207. package/src/cli/utils/app-inferrer.ts +0 -63
  208. package/src/cli/utils/app-mobile.ts +0 -113
  209. package/src/cli/utils/app-types.ts +0 -248
  210. package/src/cli/utils/app.ts +0 -6
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { handleCheckLint } from "../../../src/tools/quality/check_lint.js";
3
+ import { exec } from "child_process";
4
+
5
+ vi.mock("child_process");
6
+
7
+ describe("handleCheckLint", () => {
8
+ const projectRoot = "/fake/project";
9
+
10
+ afterEach(() => {
11
+ vi.clearAllMocks();
12
+ });
13
+
14
+ it("should execute the lint command and return output on success", async () => {
15
+ const args = {};
16
+
17
+ vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
18
+ // @ts-expect-error: Mock implementation callback type is complex
19
+ callback(null, "All good!", "");
20
+ return {} as any;
21
+ });
22
+
23
+ const result = await handleCheckLint(projectRoot, args);
24
+
25
+ expect(exec).toHaveBeenCalledWith("npm run lint", { cwd: projectRoot, timeout: 60000 }, expect.any(Function));
26
+ expect(result.isError).toBeUndefined();
27
+ expect(result.content[0].text).toContain("All good!");
28
+ });
29
+
30
+ it("should execute the lint command and return output on failure (lint issues found)", async () => {
31
+ const args = {};
32
+ const lintErrorOutput = "Error: 2 problems (2 errors, 0 warnings)";
33
+
34
+ vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
35
+ // @ts-expect-error: Mock implementation callback type is complex
36
+ callback({ code: 1, message: "Lint errors found" }, lintErrorOutput, "");
37
+ return {} as any;
38
+ });
39
+
40
+ const result = await handleCheckLint(projectRoot, args);
41
+
42
+ expect(exec).toHaveBeenCalledWith("npm run lint", { cwd: projectRoot, timeout: 60000 }, expect.any(Function));
43
+ expect(result.isError).toBe(true); // Implementation returns isError: true on failure
44
+ expect(result.content[0].text).toContain(lintErrorOutput);
45
+ });
46
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { handleRunCommand } from "../../../src/tools/shell/run_command.js";
3
+ import { exec } from "child_process";
4
+
5
+ vi.mock("child_process");
6
+
7
+ describe("handleRunCommand", () => {
8
+ const projectRoot = "/fake/project";
9
+
10
+ afterEach(() => {
11
+ vi.clearAllMocks();
12
+ });
13
+
14
+ it("should execute an allowed command", async () => {
15
+ const args = { command: "git status" };
16
+
17
+ vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
18
+ // @ts-expect-error: Mock implementation callback type is complex
19
+ callback(null, "On branch main", "");
20
+ return {} as any;
21
+ });
22
+
23
+ const result = await handleRunCommand(projectRoot, args);
24
+
25
+ expect(exec).toHaveBeenCalledWith("git status", { cwd: projectRoot, timeout: 30000 }, expect.any(Function));
26
+ expect(result.isError).toBeUndefined();
27
+ expect(result.content[0].text).toContain("On branch main");
28
+ });
29
+
30
+ it("should reject a disallowed command", async () => {
31
+ const args = { command: "rm -rf /" };
32
+ const result = await handleRunCommand(projectRoot, args);
33
+
34
+ expect(exec).not.toHaveBeenCalled();
35
+ expect(result.isError).toBe(true);
36
+ expect(result.content[0].text).toContain("Command not allowed");
37
+ });
38
+
39
+ it("should handle command failure", async () => {
40
+ const args = { command: "npm run build" };
41
+
42
+ vi.mocked(exec).mockImplementation((_cmd, _opts, callback) => {
43
+ // @ts-expect-error: Mock implementation callback type is complex
44
+ callback({ code: 1, message: "Build failed" }, "", "Error details");
45
+ return {} as any;
46
+ });
47
+
48
+ const result = await handleRunCommand(projectRoot, args);
49
+
50
+ expect(exec).toHaveBeenCalledWith("npm run build", { cwd: projectRoot, timeout: 30000 }, expect.any(Function));
51
+ expect(result.isError).toBe(true);
52
+ expect(result.content[0].text).toContain("Command failed with exit code 1");
53
+ expect(result.content[0].text).toContain("Error details");
54
+ });
55
+ });
@@ -0,0 +1,14 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "rootDir": "src",
7
+ "outDir": "./dist",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "esModuleInterop": true,
11
+ "types": ["node"]
12
+ },
13
+ "include": ["src/**/*.ts"]
14
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-enderun",
3
- "version": "1.10.4",
3
+ "version": "1.11.1",
4
4
  "description": "The Supreme AI Governance & Autonomous Orchestration Framework for Enterprise Development. Acts as a Corporate AI Management Assistant.",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -33,6 +33,8 @@
33
33
  "bin",
34
34
  "dist",
35
35
  "src",
36
+ "templates",
37
+ "framework-mcp",
36
38
  "README.md",
37
39
  "LICENSE"
38
40
  ],
@@ -58,7 +60,7 @@
58
60
  },
59
61
  "devDependencies": {
60
62
  "@eslint/js": "^10.0.1",
61
- "@modelcontextprotocol/sdk": "^1.26.0",
63
+ "@modelcontextprotocol/sdk": "^1.29.0",
62
64
  "@pandacss/dev": "^1.11.1",
63
65
  "@types/node": "^25.9.1",
64
66
  "eslint": "^10.4.0",
@@ -69,7 +71,7 @@
69
71
  "vitest": "^3.0.0"
70
72
  },
71
73
  "enderun": {
72
- "version": "1.10.3",
74
+ "version": "1.11.1",
73
75
  "initializedAt": "2026-06-04T18:51:28.970Z",
74
76
  "frameworkDir": ".enderun"
75
77
  },
@@ -3,8 +3,8 @@ import path from "path";
3
3
  import { writeJsonFile } from "../utils/fs.js";
4
4
  import { getPackageRoot } from "../utils/pkg.js";
5
5
 
6
- import type { AdapterConfig, AdapterId } from "../../modules/adapters/types.js";
7
6
  import { ADAPTER_CONFIGS, POST_INIT_HANDLERS } from "../../modules/adapters/definitions.js";
7
+ import type { AdapterConfig, AdapterId } from "../../modules/adapters/types.js";
8
8
 
9
9
  export const ADAPTERS: Record<AdapterId, AdapterConfig> = ADAPTER_CONFIGS;
10
10
 
@@ -16,7 +16,6 @@ export const FRAMEWORK_DIR_CANDIDATES = [
16
16
  ".claude",
17
17
  ".github",
18
18
  ".grok",
19
- ".windsurf",
20
19
  ".antigravity",
21
20
  ".agent",
22
21
  ".gemini/antigravity-cli",
@@ -28,7 +27,7 @@ export const FRAMEWORK_DIR_CANDIDATES = [
28
27
  export function buildMcpServerEntry(projectRoot: string) {
29
28
  const packageRoot = getPackageRoot();
30
29
  const mcpServerPath = path.join(packageRoot, "framework-mcp/dist/index.js");
31
-
30
+
32
31
  if (!fs.existsSync(mcpServerPath)) {
33
32
  console.warn(`āš ļø MCP Server not found at ${mcpServerPath}. Did you run 'npm run build'?`);
34
33
  }
@@ -2,3 +2,4 @@ export { ADAPTER_IDS, type AdapterConfig, type AdapterId, type AdapterRole } fro
2
2
  export { ADAPTERS, FRAMEWORK_DIR_CANDIDATES, runAdapterPostInit, buildMcpServerEntry } from "./core.js";
3
3
  export { resolveAdapter, isAdapterShimFile, remapFrameworkContent } from "./utils.js";
4
4
  export { scaffoldAgents } from "./scaffold.js";
5
+ export { resolveAgentsDir, mirrorUnifiedAgentsToNative } from "./paths.js";
@@ -14,12 +14,22 @@ import {
14
14
  import type { AdapterId } from "../../modules/adapters/types.js";
15
15
  import { ADAPTERS } from "./core.js";
16
16
 
17
- export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun: boolean, agentsToScaffold?: string[]): void {
17
+ export function scaffoldAgents(
18
+ projectRoot: string,
19
+ adapterId: AdapterId,
20
+ dryRun: boolean,
21
+ agentsToScaffold?: string[],
22
+ explicitDestDir?: string,
23
+ explicitExt?: string
24
+ ): void {
18
25
  const adapter = ADAPTERS[adapterId];
19
- if (!adapter || !adapter.agentsDir || !adapter.agentsExt) return;
26
+ if (!adapter) return;
20
27
 
21
28
  const allowedAgents = agentsToScaffold ? new Set(agentsToScaffold) : undefined;
22
- const destAgentsDir = path.join(projectRoot, adapter.agentsDir);
29
+ const destAgentsDir = explicitDestDir ? path.join(projectRoot, explicitDestDir) : (adapter.agentsDir ? path.join(projectRoot, adapter.agentsDir) : null);
30
+ const extension = explicitExt || adapter.agentsExt || ".md";
31
+
32
+ if (!destAgentsDir) return;
23
33
 
24
34
  const baseKnowledgeDir = path.join(getPackageRoot(), "templates/standards");
25
35
 
@@ -30,7 +40,7 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
30
40
  if (allowedAgents && !allowedAgents.has(agent.name)) continue;
31
41
 
32
42
  let content = "";
33
- let fileName = `${agent.name}${adapter.agentsExt}`;
43
+ let fileName = `${agent.name}${extension}`;
34
44
  let secondaryContent: string | null = null;
35
45
  let secondaryFileName: string | null = null;
36
46
 
@@ -38,6 +48,10 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
38
48
  case "gemini":
39
49
  content = toGeminiCliMd(agent, baseKnowledgeDir);
40
50
  break;
51
+ case "grok":
52
+ // Grok uses same Gemini-compatible YAML format
53
+ content = toGeminiCliMd(agent, baseKnowledgeDir);
54
+ break;
41
55
  case "claude":
42
56
  content = toClaudeCodeMd(agent, baseKnowledgeDir);
43
57
  break;
@@ -52,7 +66,7 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
52
66
  const agentDir = path.join(destAgentsDir, agent.name);
53
67
  if (!dryRun) fs.mkdirSync(agentDir, { recursive: true });
54
68
 
55
- content = toAntigravityJson(agent);
69
+ content = toAntigravityJson(agent, baseKnowledgeDir);
56
70
  fileName = path.join(agent.name, "agent.json");
57
71
 
58
72
  secondaryContent = `# šŸŽ–ļø Agent Enderun — @${agent.name}\n\n${agent.instructions.identity}\n\n${agent.instructions.mission}`;
@@ -72,8 +86,7 @@ export function scaffoldAgents(projectRoot: string, adapterId: AdapterId, dryRun
72
86
  }
73
87
  }
74
88
  }
75
- console.warn(`āœ… Generated ${allowedAgents ? allowedAgents.size : ALL_AGENTS.length} Agent/Rule definitions under ${path.relative(projectRoot, destAgentsDir)}/`);
76
89
  } catch (e) {
77
- console.warn(`āš ļø Failed to scaffold agents: ${e}`);
90
+ console.warn(`āš ļø Failed to scaffold agents for ${adapterId}: ${e}`);
78
91
  }
79
92
  }
@@ -3,7 +3,8 @@ import path from "path";
3
3
  import {
4
4
  remapFrameworkContent,
5
5
  type AdapterConfig,
6
- type AdapterId
6
+ type AdapterId,
7
+ ADAPTERS
7
8
  } from "../../adapters/index.js";
8
9
  import { SHIM_TEMPLATES } from "../../shims.js";
9
10
  import { writeJsonFile, writeTextFile } from "../../utils/fs.js";
@@ -38,7 +39,14 @@ export function scaffoldConstitution(targetDir: string, frameworkDir: string, ad
38
39
  console.warn(`āœ… Constitution file created inside: ${frameworkDir}/ENDERUN.md${readSuccess ? "" : " (default template)"}`);
39
40
  }
40
41
 
41
- export function scaffoldFrameworkConfigs(targetDir: string, fDir: string, adapter: AdapterConfig, dryRun: boolean, selectedPalette: string) {
42
+ export function scaffoldFrameworkConfigs(
43
+ targetDir: string,
44
+ fDir: string,
45
+ adapter: AdapterConfig,
46
+ dryRun: boolean,
47
+ selectedPalette: string,
48
+ options?: { unified?: boolean; adapters?: string[] }
49
+ ) {
42
50
  if (dryRun) return;
43
51
  const frameworkDir = path.join(targetDir, fDir);
44
52
  const palette = COLOR_PALETTES[selectedPalette as keyof typeof COLOR_PALETTES] || COLOR_PALETTES["Modern Blue"];
@@ -46,12 +54,28 @@ export function scaffoldFrameworkConfigs(targetDir: string, fDir: string, adapte
46
54
  const config = {
47
55
  name: FRAMEWORK_NAME,
48
56
  version: getPackageVersion(),
57
+ unified: options?.unified || false,
58
+ adapters: options?.adapters || [adapter.id],
49
59
  theme: {
50
60
  palette: selectedPalette,
51
61
  colors: palette
52
62
  }
53
63
  };
54
64
  writeJsonFile(path.join(frameworkDir, "config.json"), config, dryRun);
65
+
66
+ // Scaffold shared-facts.json in memory-graph
67
+ const graphDir = path.join(frameworkDir, "memory-graph");
68
+ if (!fs.existsSync(graphDir)) fs.mkdirSync(graphDir, { recursive: true });
69
+ const sharedFactsPath = path.join(graphDir, "shared-facts.json");
70
+ if (!fs.existsSync(sharedFactsPath)) {
71
+ writeJsonFile(sharedFactsPath, {
72
+ project: FRAMEWORK_NAME,
73
+ initializedAt: new Date().toISOString(),
74
+ stack: [],
75
+ policies: []
76
+ }, dryRun);
77
+ }
78
+
55
79
  let statusContent = "# šŸŽ–ļø Status\n\n| Agent | State | Active Task | Last Updated | Notes | Extra | Backup |\n|---|---|---|---|---|---|---|\n";
56
80
  for (const ag of ALL_AGENTS) {
57
81
  statusContent += "| @" + ag.name + " | READY | Idle | - | - | - | - |\n";
@@ -59,13 +83,28 @@ export function scaffoldFrameworkConfigs(targetDir: string, fDir: string, adapte
59
83
  writeTextFile(path.join(frameworkDir, "STATUS.md"), statusContent);
60
84
  }
61
85
 
62
- export function scaffoldShims(projectRoot: string, coreDir: string, adapterId: AdapterId, adapter: AdapterConfig, dryRun: boolean) {
86
+ export function scaffoldShims(
87
+ projectRoot: string,
88
+ coreDir: string,
89
+ adapterId: AdapterId,
90
+ adapter: AdapterConfig,
91
+ dryRun: boolean,
92
+ unified: boolean = false
93
+ ) {
63
94
  for (const [name, content] of Object.entries(SHIM_TEMPLATES)) {
64
- if (name.toLowerCase() === adapterId.split("-")[0] || name === adapterId) {
95
+ const isSelectedAdapter = name.toLowerCase() === adapterId.split("-")[0] || name === adapterId;
96
+
97
+ if (unified || isSelectedAdapter) {
65
98
  const shimContent = remapFrameworkContent(content, coreDir, adapterId);
66
- const shimFileName = adapter.shimFile || `${name.toUpperCase()}.md`;
99
+ const shimAdapter = ADAPTERS[name as AdapterId] || adapter;
100
+ const shimFileName = (unified && !isSelectedAdapter) ? (shimAdapter.shimFile || `${name.toUpperCase()}.md`) : (adapter.shimFile || `${name.toUpperCase()}.md`);
101
+
67
102
  if (!dryRun) writeTextFile(path.join(projectRoot, shimFileName), shimContent);
68
- console.warn(`āœ… Platform shim created: ${shimFileName}`);
103
+ if (isSelectedAdapter) {
104
+ console.warn(`āœ… Platform shim created: ${shimFileName}`);
105
+ } else if (unified) {
106
+ console.warn(`āœ… Unified platform shim added: ${shimFileName}`);
107
+ }
69
108
  }
70
109
  }
71
110
  }
@@ -5,6 +5,9 @@ import {
5
5
  resolveAdapter,
6
6
  runAdapterPostInit,
7
7
  scaffoldAgents,
8
+ resolveAgentsDir,
9
+ mirrorUnifiedAgentsToNative,
10
+ ADAPTER_IDS,
8
11
  type AdapterId,
9
12
  } from "../adapters/index.js";
10
13
  import { ensureDir } from "../utils/fs.js";
@@ -112,15 +115,41 @@ export async function initCommand(adapterName: string, options: { unified?: bool
112
115
  }
113
116
 
114
117
  scaffoldConstitution(projectRoot, coreDir, adapterId, dryRun);
118
+ scaffoldFrameworkConfigs(projectRoot, coreDir, adapter, dryRun, selectedPalette, {
119
+ unified: isUnified,
120
+ adapters: isUnified ? [...ADAPTER_IDS] : [adapterId]
121
+ });
115
122
 
116
123
  scaffoldStandards(path.join(projectRoot, coreDir), dryRun);
117
- scaffoldAgents(projectRoot, adapterId, dryRun, selectedAgents);
124
+
125
+ if (isUnified) {
126
+ // Scaffold ALL agents for ALL adapters under unified hub
127
+ for (const id of ADAPTER_IDS) {
128
+ const dest = resolveAgentsDir(id, true, aiToolDir);
129
+ scaffoldAgents(projectRoot, id, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
130
+ if (!dryRun) mirrorUnifiedAgentsToNative(projectRoot, id);
131
+ }
132
+ UI.success(`āœ… Scaffolding complete for all adapters under ${aiToolDir}/ with native mirrors.`);
133
+ } else {
134
+ // Standard single-adapter scaffold
135
+ const dest = resolveAgentsDir(adapterId, false);
136
+ scaffoldAgents(projectRoot, adapterId, dryRun, selectedAgents, dest.agentsDir, dest.agentsExt);
137
+ UI.success(`āœ… Generated agent definitions under ${dest.agentsDir}/`);
138
+ }
118
139
 
119
140
  const skillsBaseDir = path.join(projectRoot, aiToolDir, "skills");
120
141
  scaffoldSkills(skillsBaseDir, dryRun);
121
142
  scaffoldOps(path.join(projectRoot, coreDir), dryRun);
122
- scaffoldShims(projectRoot, coreDir, adapterId, adapter, dryRun);
143
+ scaffoldShims(projectRoot, coreDir, adapterId, adapter, dryRun, isUnified);
144
+
145
+ // Initialize runtime directories
146
+ if (!dryRun) {
147
+ ensureDir(path.join(projectRoot, coreDir, "messages"));
148
+ ensureDir(path.join(projectRoot, coreDir, "logs"));
149
+ ensureDir(path.join(projectRoot, coreDir, "memory-graph"));
150
+ }
123
151
 
152
+ initializeMemory(path.join(projectRoot, coreDir), dryRun);
124
153
  runAdapterPostInit(adapter, projectRoot);
125
154
 
126
155
  UI.success(`\nšŸš€ ${FRAMEWORK_NAME} (v${getPackageVersion()}) initialized successfully!`);
@@ -28,11 +28,16 @@ export type HermesMessage = z.infer<typeof HermesMessageSchema>;
28
28
  let agentStatusCache: Record<string, { state: string; task: string; lastUpdated?: string }> = {};
29
29
  let isLooping = false;
30
30
 
31
- export async function orchestrateCommand() {
31
+ export async function orchestrateCommand(options?: { maxIterations?: number }) {
32
32
  UI.intent("Hermes Message Broker", "Starting the live agent orchestration loop...");
33
33
 
34
34
  const frameworkDir = getFrameworkDir();
35
35
  const messagesDir = path.join(frameworkDir, "messages");
36
+ const maxIterations = options?.maxIterations;
37
+ let iterationCount = 0;
38
+
39
+ // Reset in-memory cache so each invocation starts fresh (important for test isolation)
40
+ agentStatusCache = {};
36
41
 
37
42
  // Graceful Shutdown Handling
38
43
  const shutdown = async () => {
@@ -93,16 +98,36 @@ export async function orchestrateCommand() {
93
98
  const parsed = JSON.parse(line);
94
99
  const msg = HermesMessageSchema.parse(parsed);
95
100
 
96
- // Contract Validation
101
+ // Contract Validation for structured task messages
102
+ // ACTION & DELEGATION must be valid TaskRequest payloads
103
+ // SUBTASK must have a parentId and valid task payload
104
+ // ALERT must have a content string (free-form, no schema required)
97
105
  if (msg.category === "ACTION" || msg.category === "DELEGATION") {
98
106
  try {
99
107
  const payload = JSON.parse(msg.content);
100
108
  TaskRequestSchema.parse(payload);
101
109
  } catch (e) {
102
- UI.error(`Invalid task contract payload: ${(e as Error).message}`);
110
+ UI.error(`Invalid task contract payload in ${msg.category} from @${msg.from}: ${(e as Error).message}`);
103
111
  return; // Skip invalid message
104
112
  }
105
113
  }
114
+ if (msg.category === "SUBTASK") {
115
+ if (!msg.parentId) {
116
+ UI.error(`SUBTASK from @${msg.from} is missing required parentId — skipping.`);
117
+ return;
118
+ }
119
+ try {
120
+ const payload = JSON.parse(msg.content);
121
+ TaskRequestSchema.parse(payload);
122
+ } catch (e) {
123
+ UI.error(`Invalid SUBTASK payload from @${msg.from}: ${(e as Error).message}`);
124
+ return;
125
+ }
126
+ }
127
+ if (msg.category === "ALERT" && !msg.content.trim()) {
128
+ UI.error(`ALERT from @${msg.from} has empty content — skipping.`);
129
+ return;
130
+ }
106
131
 
107
132
  // A message is actionable if it's pending, or if it's been approved.
108
133
  if (msg.status === "PENDING" || msg.status === "APPROVED") {
@@ -227,6 +252,13 @@ export async function orchestrateCommand() {
227
252
  logger.debug("Hermes global loop failure", globalLoopErr);
228
253
  }
229
254
 
255
+ iterationCount++;
256
+ // If maxIterations is set (e.g. in tests), stop after N iterations without sleeping
257
+ if (maxIterations !== undefined && iterationCount >= maxIterations) {
258
+ isLooping = false;
259
+ break;
260
+ }
261
+
230
262
  // Prevent 100% CPU and provide breathing room for I/O
231
263
  await sleep(2000);
232
264
  }
@@ -295,7 +327,12 @@ export async function sendMessage(args: {
295
327
 
296
328
  try {
297
329
  const defaultPriority = (args.category === "ALERT" || args.category === "ACTION") ? "HIGH" : "NORMAL";
298
- const requiresApproval = args.requiresApproval !== undefined ? args.requiresApproval : (args.category === "ALERT" || args.category === "ACTION");
330
+ // Only ALERT requires manager approval by default.
331
+ // ACTION messages flow freely unless the caller explicitly sets requiresApproval=true.
332
+ // This prevents workflow blockage on normal agent-to-agent task delegation.
333
+ const requiresApproval = args.requiresApproval !== undefined
334
+ ? args.requiresApproval
335
+ : args.category === "ALERT";
299
336
 
300
337
  const message: HermesMessage = {
301
338
  timestamp: new Date().toISOString(),
@@ -1,47 +1,113 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { updateDocumentStore } from "../utils/memory.js";
4
3
  import { generateULID } from "../utils/time.js";
5
4
  import { UI } from "../utils/ui.js";
6
5
 
7
6
  /**
8
- * Parses docs/user/roadmap.md and injects tasks into the Document Store.
7
+ * Reads ALL markdown files from the docs/ directory and creates
8
+ * planning tasks from them. Agents will use this to understand
9
+ * project requirements and generate code accordingly.
9
10
  */
10
11
  export async function planCommand() {
11
12
  const projectRoot = process.cwd();
12
- const roadmapPath = path.join(projectRoot, "docs/user/roadmap.md");
13
+ const docsDir = path.join(projectRoot, "docs");
13
14
 
14
- if (!fs.existsSync(roadmapPath)) {
15
- UI.error("Roadmap file not found at docs/user/roadmap.md");
15
+ if (!fs.existsSync(docsDir)) {
16
+ UI.error("Docs directory not found at docs/");
17
+ console.warn("šŸ’” Create a docs/ folder with your project requirements in .md files.");
16
18
  return;
17
19
  }
18
20
 
19
- const content = fs.readFileSync(roadmapPath, "utf8");
20
- const taskRegex = /- \[ \] (.*) \| (.*) \| (.*)/g;
21
- let match;
22
- let count = 0;
21
+ const entries = fs.readdirSync(docsDir, { withFileTypes: true });
22
+ const mdFiles = entries.filter(e => e.isFile() && e.name.endsWith(".md"));
23
23
 
24
- UI.intent("Planning Engine", "Parsing roadmap.md and injecting tasks into Document Store...");
24
+ if (mdFiles.length === 0) {
25
+ UI.warning("No markdown files found in docs/ directory.");
26
+ console.warn("šŸ’” Add .md files to docs/ with your project requirements.");
27
+ return;
28
+ }
25
29
 
26
- while ((match = taskRegex.exec(content)) !== null) {
27
- const description = match[1];
28
- const priority = match[2];
29
- const agent = match[3];
30
+ UI.intent("Planning Engine", `Reading ${mdFiles.length} document(s) from docs/...`);
31
+
32
+ // Discover available template standards
33
+ const templatesDir = path.join(projectRoot, "templates");
34
+ const standards: string[] = [];
35
+ if (fs.existsSync(templatesDir)) {
36
+ const templateFiles = fs.readdirSync(templatesDir);
37
+ standards.push(...templateFiles.filter(f => f.endsWith("-standards.md")).map(f => `templates/${f}`));
38
+ if (standards.length > 0) {
39
+ UI.success(`Found ${standards.length} standard templates available for code generation.`);
40
+ }
41
+ }
42
+
43
+ let totalTasks = 0;
44
+
45
+ for (const file of mdFiles) {
46
+ const filePath = path.join(docsDir, file.name);
47
+ const content = fs.readFileSync(filePath, "utf8");
48
+ const lines = content.split("\n");
30
49
  const traceId = generateULID();
31
-
50
+
51
+ UI.success(`šŸ“„ docs/${file.name} (${lines.length} lines) → Trace: ${traceId}`);
52
+
53
+ console.warn(` Content preview: ${content.substring(0, 200).replace(/\n/g, " ")}...`);
54
+
55
+ // Extract headings as task descriptions
56
+ const headingRegex = /^#{2,4}\s+(.+)$/gm;
57
+ let headingMatch;
58
+ let headingCount = 0;
59
+ while ((headingMatch = headingRegex.exec(content)) !== null) {
60
+ headingCount++;
61
+ totalTasks++;
62
+ }
63
+
64
+ // Extract checklist items
65
+ const taskRegex = /- \[ \]\s+(.+)/g;
66
+ let taskMatch;
67
+ let taskCount = 0;
68
+ while ((taskMatch = taskRegex.exec(content)) !== null) {
69
+ if (taskMatch[1].trim().length >= 3) {
70
+ taskCount++;
71
+ totalTasks++;
72
+ }
73
+ }
74
+
75
+ console.warn(` šŸ“‹ ${headingCount} sections, ${taskCount} actionable tasks detected`);
76
+
77
+ // Store in project memory-compatible format
78
+ const memoryDir = path.join(projectRoot, ".enderun", "memory", "tasks");
79
+ if (!fs.existsSync(memoryDir)) {
80
+ fs.mkdirSync(memoryDir, { recursive: true });
81
+ }
82
+
83
+ const taskFile = path.join(memoryDir, `${traceId}.json`);
32
84
  const taskData = {
33
85
  traceId,
34
- description: description.trim(),
35
- priority: priority.trim(),
36
- agent: agent.trim().replace("@", ""),
86
+ source: `docs/${file.name}`,
87
+ description: `Process requirements from docs/${file.name}`,
37
88
  status: "PENDING",
38
- createdAt: new Date().toISOString()
89
+ createdAt: new Date().toISOString(),
90
+ standards,
91
+ headings: headingCount,
92
+ tasks: taskCount,
93
+ preview: content.substring(0, 500),
39
94
  };
95
+ fs.writeFileSync(taskFile, JSON.stringify(taskData, null, 2));
96
+ }
40
97
 
41
- updateDocumentStore("task", taskData, traceId);
42
- UI.success(`Injected task: ${taskData.description} (Agent: ${taskData.agent})`);
43
- count++;
98
+ // Log available standards
99
+ if (standards.length > 0) {
100
+ console.warn("");
101
+ UI.divider();
102
+ console.warn("šŸ“š Available Enterprise Standards:");
103
+ standards.forEach(s => console.warn(` - ${s}`));
104
+ UI.divider();
44
105
  }
45
106
 
46
- UI.success(`Plan complete: ${count} tasks injected into Document Store.`);
107
+ UI.success(`\nāœ… Planning complete: ${totalTasks} tasks identified from ${mdFiles.length} document(s).`);
108
+ console.warn("\nšŸ“‹ Next steps:");
109
+ console.warn(" 1. Run 'agent-enderun status' to see project state");
110
+ console.warn(" 2. AI agents (Claude, Gemini, Grok, etc.) will read docs/ and templates/");
111
+ console.warn(" 3. Agents generate enterprise-standard code based on requirements");
112
+ console.warn(" 4. Use @agent delegation for specific tasks: agent-enderun @backend \"...\"");
47
113
  }