agent-enderun 1.1.5 → 1.1.7

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 (253) hide show
  1. package/ENDERUN.md +13 -10
  2. package/README.md +14 -31
  3. package/bin/run-multi-test.js +77 -0
  4. package/dist/framework-mcp/src/tools/dashboard/start_dashboard.d.ts +5 -0
  5. package/dist/framework-mcp/src/tools/dashboard/start_dashboard.js +30 -0
  6. package/dist/framework-mcp/src/tools/dashboard/start_dashboard.js.map +1 -0
  7. package/dist/framework-mcp/src/tools/definitions.js +118 -0
  8. package/dist/framework-mcp/src/tools/definitions.js.map +1 -1
  9. package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.d.ts +5 -0
  10. package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js +51 -0
  11. package/dist/framework-mcp/src/tools/file_system/batch_surgical_edit.js.map +1 -0
  12. package/dist/framework-mcp/src/tools/file_system/replace_text.js +8 -4
  13. package/dist/framework-mcp/src/tools/file_system/replace_text.js.map +1 -1
  14. package/dist/framework-mcp/src/tools/file_system/write_file.js +3 -0
  15. package/dist/framework-mcp/src/tools/file_system/write_file.js.map +1 -1
  16. package/dist/framework-mcp/src/tools/framework/audit_deps.d.ts +6 -0
  17. package/dist/framework-mcp/src/tools/framework/audit_deps.js +42 -0
  18. package/dist/framework-mcp/src/tools/framework/audit_deps.js.map +1 -0
  19. package/dist/framework-mcp/src/tools/framework/run_tests.d.ts +5 -0
  20. package/dist/framework-mcp/src/tools/framework/run_tests.js +26 -0
  21. package/dist/framework-mcp/src/tools/framework/run_tests.js.map +1 -0
  22. package/dist/framework-mcp/src/tools/index.js +24 -0
  23. package/dist/framework-mcp/src/tools/index.js.map +1 -1
  24. package/dist/framework-mcp/src/tools/memory/get_insights.d.ts +6 -0
  25. package/dist/framework-mcp/src/tools/memory/get_insights.js +35 -0
  26. package/dist/framework-mcp/src/tools/memory/get_insights.js.map +1 -0
  27. package/dist/framework-mcp/src/tools/memory/read_memory.d.ts +6 -0
  28. package/dist/framework-mcp/src/tools/memory/read_memory.js +29 -0
  29. package/dist/framework-mcp/src/tools/memory/read_memory.js.map +1 -0
  30. package/dist/framework-mcp/src/tools/messaging/send_message.js +1 -1
  31. package/dist/framework-mcp/src/tools/messaging/send_message.js.map +1 -1
  32. package/dist/framework-mcp/src/tools/observability/check_ports.d.ts +5 -0
  33. package/dist/framework-mcp/src/tools/observability/check_ports.js +27 -0
  34. package/dist/framework-mcp/src/tools/observability/check_ports.js.map +1 -0
  35. package/dist/framework-mcp/src/tools/observability/get_health.d.ts +5 -0
  36. package/dist/framework-mcp/src/tools/observability/get_health.js +21 -0
  37. package/dist/framework-mcp/src/tools/observability/get_health.js.map +1 -0
  38. package/dist/framework-mcp/src/tools/search/get_gaps.d.ts +6 -0
  39. package/dist/framework-mcp/src/tools/search/get_gaps.js +49 -0
  40. package/dist/framework-mcp/src/tools/search/get_gaps.js.map +1 -0
  41. package/dist/framework-mcp/src/tools/search/get_map.d.ts +6 -0
  42. package/dist/framework-mcp/src/tools/search/get_map.js +45 -0
  43. package/dist/framework-mcp/src/tools/search/get_map.js.map +1 -0
  44. package/dist/framework-mcp/src/tools/search/grep_search.d.ts +5 -0
  45. package/dist/framework-mcp/src/tools/search/grep_search.js +60 -0
  46. package/dist/framework-mcp/src/tools/search/grep_search.js.map +1 -0
  47. package/dist/framework-mcp/src/tools/search/list_dir.d.ts +5 -0
  48. package/dist/framework-mcp/src/tools/search/list_dir.js +29 -0
  49. package/dist/framework-mcp/src/tools/search/list_dir.js.map +1 -0
  50. package/dist/framework-mcp/src/tools/types.d.ts +10 -5
  51. package/dist/framework-mcp/src/utils/compliance.d.ts +5 -0
  52. package/dist/framework-mcp/src/utils/compliance.js +30 -0
  53. package/dist/framework-mcp/src/utils/compliance.js.map +1 -0
  54. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js +5 -5
  55. package/dist/framework-mcp/tests/tools/messaging/send_message.test.js.map +1 -1
  56. package/dist/src/cli/adapters/types.d.ts +2 -2
  57. package/dist/src/cli/adapters.d.ts +1 -1
  58. package/dist/src/cli/adapters.js +45 -77
  59. package/dist/src/cli/adapters.js.map +1 -1
  60. package/dist/src/cli/commands/check.js +52 -6
  61. package/dist/src/cli/commands/check.js.map +1 -1
  62. package/dist/src/cli/commands/init.d.ts +5 -1
  63. package/dist/src/cli/commands/init.js +184 -106
  64. package/dist/src/cli/commands/init.js.map +1 -1
  65. package/dist/src/cli/commands/orchestrate.d.ts +3 -3
  66. package/dist/src/cli/commands/orchestrate.js +14 -8
  67. package/dist/src/cli/commands/orchestrate.js.map +1 -1
  68. package/dist/src/cli/commands/status.js +3 -2
  69. package/dist/src/cli/commands/status.js.map +1 -1
  70. package/dist/src/cli/index.js +4 -3
  71. package/dist/src/cli/index.js.map +1 -1
  72. package/dist/src/cli/shims.js +6 -6
  73. package/dist/src/cli/utils/app-backend.d.ts +2 -0
  74. package/dist/src/cli/utils/app-backend.js +236 -0
  75. package/dist/src/cli/utils/app-backend.js.map +1 -0
  76. package/dist/src/cli/utils/app-docs.d.ts +3 -0
  77. package/dist/src/cli/utils/app-docs.js +59 -0
  78. package/dist/src/cli/utils/app-docs.js.map +1 -0
  79. package/dist/src/cli/utils/app-frontend.d.ts +2 -0
  80. package/dist/src/cli/utils/app-frontend.js +248 -0
  81. package/dist/src/cli/utils/app-frontend.js.map +1 -0
  82. package/dist/src/cli/utils/app-inferrer.d.ts +14 -0
  83. package/dist/src/cli/utils/app-inferrer.js +39 -0
  84. package/dist/src/cli/utils/app-inferrer.js.map +1 -0
  85. package/dist/src/cli/utils/app-types.d.ts +3 -0
  86. package/dist/src/cli/utils/app-types.js +233 -0
  87. package/dist/src/cli/utils/app-types.js.map +1 -0
  88. package/dist/src/cli/utils/app.d.ts +5 -32
  89. package/dist/src/cli/utils/app.js +5 -794
  90. package/dist/src/cli/utils/app.js.map +1 -1
  91. package/dist/src/cli/utils/memory.js +8 -4
  92. package/dist/src/cli/utils/memory.js.map +1 -1
  93. package/dist/src/modules/adapters/antigravity-cli.js +3 -3
  94. package/dist/src/modules/adapters/antigravity-cli.js.map +1 -1
  95. package/dist/src/modules/adapters/claude.js +1 -1
  96. package/dist/src/modules/adapters/claude.js.map +1 -1
  97. package/dist/src/modules/adapters/codex.js +2 -2
  98. package/dist/src/modules/adapters/codex.js.map +1 -1
  99. package/dist/src/modules/adapters/cursor.js +1 -1
  100. package/dist/src/modules/adapters/cursor.js.map +1 -1
  101. package/dist/src/modules/adapters/definitions.d.ts +9 -0
  102. package/dist/src/modules/adapters/definitions.js +124 -0
  103. package/dist/src/modules/adapters/definitions.js.map +1 -0
  104. package/dist/src/modules/adapters/gemini.js +2 -2
  105. package/dist/src/modules/adapters/gemini.js.map +1 -1
  106. package/dist/src/modules/adapters/grok.js +1 -1
  107. package/dist/src/modules/adapters/grok.js.map +1 -1
  108. package/dist/src/modules/agents/definitions.js +26 -27
  109. package/dist/src/modules/agents/definitions.js.map +1 -1
  110. package/dist/src/shared/config.d.ts +3 -3
  111. package/dist/src/shared/logger.js +8 -5
  112. package/dist/src/shared/logger.js.map +1 -1
  113. package/dist/tests/adapter.test.d.ts +1 -0
  114. package/dist/tests/adapter.test.js +129 -0
  115. package/dist/tests/adapter.test.js.map +1 -0
  116. package/dist/tests/agents-definitions.test.d.ts +1 -0
  117. package/dist/tests/agents-definitions.test.js +54 -0
  118. package/dist/tests/agents-definitions.test.js.map +1 -0
  119. package/dist/tests/approve.test.d.ts +1 -0
  120. package/dist/tests/approve.test.js +88 -0
  121. package/dist/tests/approve.test.js.map +1 -0
  122. package/dist/tests/config.test.d.ts +1 -0
  123. package/dist/tests/config.test.js +58 -0
  124. package/dist/tests/config.test.js.map +1 -0
  125. package/dist/tests/container.runner.d.ts +1 -0
  126. package/dist/tests/container.runner.js +68 -0
  127. package/dist/tests/container.runner.js.map +1 -0
  128. package/dist/tests/container.test.d.ts +1 -0
  129. package/dist/tests/container.test.js +73 -0
  130. package/dist/tests/container.test.js.map +1 -0
  131. package/dist/tests/errors.test.d.ts +1 -0
  132. package/dist/tests/errors.test.js +64 -0
  133. package/dist/tests/errors.test.js.map +1 -0
  134. package/dist/tests/fs-utils.test.d.ts +1 -0
  135. package/dist/tests/fs-utils.test.js +101 -0
  136. package/dist/tests/fs-utils.test.js.map +1 -0
  137. package/dist/tests/logger.test.d.ts +1 -0
  138. package/dist/tests/logger.test.js +81 -0
  139. package/dist/tests/logger.test.js.map +1 -0
  140. package/dist/tests/memory-utils.test.d.ts +1 -0
  141. package/dist/tests/memory-utils.test.js +173 -0
  142. package/dist/tests/memory-utils.test.js.map +1 -0
  143. package/dist/tests/orchestrate.test.d.ts +1 -0
  144. package/dist/tests/orchestrate.test.js +131 -0
  145. package/dist/tests/orchestrate.test.js.map +1 -0
  146. package/dist/tests/skills-definitions.test.d.ts +1 -0
  147. package/dist/tests/skills-definitions.test.js +34 -0
  148. package/dist/tests/skills-definitions.test.js.map +1 -0
  149. package/dist/tests/status.test.d.ts +1 -0
  150. package/dist/tests/status.test.js +105 -0
  151. package/dist/tests/status.test.js.map +1 -0
  152. package/dist/tests/string.test.d.ts +1 -0
  153. package/dist/tests/string.test.js +89 -0
  154. package/dist/tests/string.test.js.map +1 -0
  155. package/dist/tests/time.test.d.ts +1 -0
  156. package/dist/tests/time.test.js +48 -0
  157. package/dist/tests/time.test.js.map +1 -0
  158. package/dist/tests/trace.test.d.ts +1 -0
  159. package/dist/tests/trace.test.js +61 -0
  160. package/dist/tests/trace.test.js.map +1 -0
  161. package/dist/vitest.config.js +1 -0
  162. package/dist/vitest.config.js.map +1 -1
  163. package/docs/getting-started.md +4 -0
  164. package/docs/user/corporate-governance.md +25 -0
  165. package/framework-mcp/dist/tools/dashboard/start_dashboard.js +29 -0
  166. package/framework-mcp/dist/tools/definitions.js +118 -0
  167. package/framework-mcp/dist/tools/file_system/batch_surgical_edit.js +50 -0
  168. package/framework-mcp/dist/tools/file_system/replace_text.js +8 -4
  169. package/framework-mcp/dist/tools/file_system/write_file.js +3 -0
  170. package/framework-mcp/dist/tools/framework/audit_deps.js +41 -0
  171. package/framework-mcp/dist/tools/framework/run_tests.js +25 -0
  172. package/framework-mcp/dist/tools/index.js +24 -0
  173. package/framework-mcp/dist/tools/memory/get_insights.js +34 -0
  174. package/framework-mcp/dist/tools/memory/read_memory.js +28 -0
  175. package/framework-mcp/dist/tools/messaging/send_message.js +1 -1
  176. package/framework-mcp/dist/tools/observability/check_ports.js +26 -0
  177. package/framework-mcp/dist/tools/observability/get_health.js +20 -0
  178. package/framework-mcp/dist/tools/search/get_gaps.js +48 -0
  179. package/framework-mcp/dist/tools/search/get_map.js +44 -0
  180. package/framework-mcp/dist/tools/search/grep_search.js +59 -0
  181. package/framework-mcp/dist/tools/search/list_dir.js +28 -0
  182. package/framework-mcp/dist/utils/compliance.js +29 -0
  183. package/framework-mcp/package.json +1 -1
  184. package/framework-mcp/src/tools/dashboard/start_dashboard.ts +33 -0
  185. package/framework-mcp/src/tools/definitions.ts +118 -0
  186. package/framework-mcp/src/tools/file_system/batch_surgical_edit.ts +70 -0
  187. package/framework-mcp/src/tools/file_system/replace_text.ts +10 -4
  188. package/framework-mcp/src/tools/file_system/write_file.ts +5 -0
  189. package/framework-mcp/src/tools/framework/audit_deps.ts +49 -0
  190. package/framework-mcp/src/tools/framework/run_tests.ts +28 -0
  191. package/framework-mcp/src/tools/index.ts +24 -0
  192. package/framework-mcp/src/tools/memory/get_insights.ts +41 -0
  193. package/framework-mcp/src/tools/memory/read_memory.ts +31 -0
  194. package/framework-mcp/src/tools/messaging/send_message.ts +1 -1
  195. package/framework-mcp/src/tools/observability/check_ports.ts +30 -0
  196. package/framework-mcp/src/tools/observability/get_health.ts +25 -0
  197. package/framework-mcp/src/tools/search/get_gaps.ts +54 -0
  198. package/framework-mcp/src/tools/search/get_map.ts +50 -0
  199. package/framework-mcp/src/tools/search/grep_search.ts +66 -0
  200. package/framework-mcp/src/tools/search/list_dir.ts +34 -0
  201. package/framework-mcp/src/tools/types.ts +11 -1
  202. package/framework-mcp/src/utils/compliance.ts +37 -0
  203. package/framework-mcp/tests/tools/messaging/send_message.test.ts +5 -5
  204. package/package.json +3 -3
  205. package/src/cli/adapters/types.ts +2 -2
  206. package/src/cli/adapters.ts +45 -80
  207. package/src/cli/commands/check.ts +52 -6
  208. package/src/cli/commands/init.ts +193 -114
  209. package/src/cli/commands/orchestrate.ts +14 -8
  210. package/src/cli/commands/status.ts +3 -2
  211. package/src/cli/index.ts +4 -3
  212. package/src/cli/shims.ts +6 -6
  213. package/src/cli/utils/app-backend.ts +249 -0
  214. package/src/cli/utils/app-docs.ts +65 -0
  215. package/src/cli/utils/app-frontend.ts +257 -0
  216. package/src/cli/utils/app-inferrer.ts +53 -0
  217. package/src/cli/utils/app-types.ts +243 -0
  218. package/src/cli/utils/app.ts +5 -849
  219. package/src/cli/utils/memory.ts +8 -4
  220. package/src/modules/adapters/definitions.ts +125 -0
  221. package/src/modules/agents/definitions.ts +26 -27
  222. package/src/shared/logger.ts +8 -5
  223. package/templates/prompts/bug-fix-recipe.md +20 -0
  224. package/templates/prompts/new-feature-recipe.md +19 -0
  225. package/templates/prompts/refactoring-recipe.md +21 -0
  226. package/templates/standards/architecture-standards.md +23 -0
  227. package/templates/standards/crud-governance.md +21 -0
  228. package/templates/standards/frontend-standards.md +38 -0
  229. package/templates/standards/i18n-standards.md +17 -0
  230. package/templates/standards/logging-and-secrets.md +29 -0
  231. package/templates/standards/mobile-standards.md +24 -0
  232. package/templates/standards/quality-standards.md +31 -0
  233. package/templates/standards/security-standards.md +21 -0
  234. package/templates/standards/tailwind-standards.md +20 -0
  235. package/templates/standards/testing-standards.md +31 -0
  236. package/src/modules/adapters/antigravity-cli.ts +0 -25
  237. package/src/modules/adapters/claude.ts +0 -36
  238. package/src/modules/adapters/codex.ts +0 -22
  239. package/src/modules/adapters/cursor.ts +0 -22
  240. package/src/modules/adapters/gemini.ts +0 -27
  241. package/src/modules/adapters/grok.ts +0 -20
  242. package/templates/architecture/agents-manifest.md +0 -79
  243. package/templates/architecture/approval-flows.md +0 -61
  244. package/templates/architecture/enterprise-architecture.md +0 -69
  245. package/templates/architecture/standards/crud-governance.md +0 -46
  246. package/templates/architecture/standards/data-fetching-patterns.md +0 -13
  247. package/templates/architecture/standards/design-system.md +0 -31
  248. package/templates/architecture/standards/documentation-ownership.md +0 -21
  249. package/templates/architecture/standards/logging.md +0 -7
  250. package/templates/architecture/standards/mobile-standards.md +0 -48
  251. package/templates/architecture/standards/tech-stack.md +0 -9
  252. package/templates/backend/error-handling.md +0 -74
  253. package/templates/frontend/component-patterns.md +0 -91
@@ -0,0 +1,249 @@
1
+ import path from "path";
2
+ import { ensureDir, writeJsonFile, writeTextFile } from "./fs.js";
3
+ import { getConfiguredPaths } from "./memory.js";
4
+ import { getDependencyVersions } from "./pkg.js";
5
+ import { createBaseTypeFiles } from "./app-types.js";
6
+ import type { AppSpec } from "./app-inferrer.js";
7
+
8
+ const targetDir = process.cwd();
9
+
10
+ export function createBackendFiles(spec: AppSpec): void {
11
+ const pathsMap = getConfiguredPaths();
12
+ const backendDir = pathsMap.backend;
13
+ const { fastify, "@fastify/cors": fastifyCors, zod, "@types/node": typesNode, tsx, typescript, "vitest-backend": vitest } = getDependencyVersions();
14
+
15
+ createBaseTypeFiles(path.join(targetDir, backendDir, "src"));
16
+ writeJsonFile(path.join(targetDir, backendDir, "contract.version.json"), {
17
+ "contract_hash": "initial_hash_placeholder",
18
+ "last_updated": new Date().toISOString()
19
+ });
20
+ writeJsonFile(path.join(targetDir, backendDir, "package.json"), {
21
+ name: "@agent-enderun/backend",
22
+ version: "0.1.0",
23
+ private: true,
24
+ type: "module",
25
+ scripts: {
26
+ dev: "tsx src/server.ts",
27
+ build: "tsc -p tsconfig.json",
28
+ start: "node dist/server.js",
29
+ test: "vitest run",
30
+ },
31
+ dependencies: {
32
+ "@fastify/cors": fastifyCors,
33
+ fastify: fastify,
34
+ zod: zod,
35
+ },
36
+ devDependencies: {
37
+ "@types/node": typesNode,
38
+ tsx: tsx,
39
+ typescript: typescript,
40
+ vitest: vitest,
41
+ },
42
+ });
43
+
44
+ writeJsonFile(path.join(targetDir, backendDir, "tsconfig.json"), {
45
+ extends: "../../tsconfig.json",
46
+ compilerOptions: {
47
+ outDir: "dist",
48
+ rootDir: "src",
49
+ module: "NodeNext",
50
+ moduleResolution: "NodeNext",
51
+ target: "ES2022",
52
+ strict: true,
53
+ skipLibCheck: true,
54
+ },
55
+ include: ["src/**/*.ts"],
56
+ });
57
+
58
+ const srcDir = path.join(targetDir, backendDir, "src");
59
+ ensureDir(path.join(srcDir, "database"));
60
+ ensureDir(path.join(srcDir, "repositories"));
61
+ ensureDir(path.join(srcDir, "services"));
62
+
63
+ writeTextFile(path.join(srcDir, "database/memoryDb.ts"), [
64
+ "import type { Customer, ReportMetric, Role, User } from \"../types/index.js\";",
65
+ "",
66
+ "const now = new Date().toISOString();",
67
+ "",
68
+ "export const rolesDb: Role[] = [",
69
+ " { id: \"role_admin\" as Role[\"id\"], name: \"Admin\", permissions: [\"users:manage\", \"reports:view\", \"customers:manage\"] },",
70
+ " { id: \"role_manager\" as Role[\"id\"], name: \"Manager\", permissions: [\"reports:view\", \"customers:manage\"] },",
71
+ " { id: \"role_viewer\" as Role[\"id\"], name: \"Viewer\", permissions: [\"reports:view\"] },",
72
+ "];",
73
+ "",
74
+ "export const usersDb: User[] = [",
75
+ " { id: \"user_1\" as User[\"id\"], email: \"admin@example.com\", fullName: \"Admin User\", role: \"ADMIN\", createdAt: now, updatedAt: now },",
76
+ " { id: \"user_2\" as User[\"id\"], email: \"manager@example.com\", fullName: \"Sales Manager\", role: \"DEVELOPER\", createdAt: now, updatedAt: now },",
77
+ "];",
78
+ "",
79
+ "export const customersDb: Customer[] = [",
80
+ " { id: \"customer_1\" as Customer[\"id\"], name: \"Northwind\", ownerId: usersDb[1].id, status: \"ACTIVE\", annualValue: 125000, createdAt: now, updatedAt: now },",
81
+ " { id: \"customer_2\" as Customer[\"id\"], name: \"Acme Corp\", ownerId: usersDb[1].id, status: \"LEAD\", annualValue: 82000, createdAt: now, updatedAt: now },",
82
+ " { id: \"customer_3\" as Customer[\"id\"], name: \"Globex\", ownerId: usersDb[0].id, status: \"AT_RISK\", annualValue: 54000, createdAt: now, updatedAt: now },",
83
+ "];",
84
+ "",
85
+ "export const reportsDb: ReportMetric[] = [",
86
+ " { id: \"report_pipeline\" as ReportMetric[\"id\"], label: \"Pipeline\", value: 261000, trend: \"UP\" },",
87
+ " { id: \"report_active_customers\" as ReportMetric[\"id\"], label: \"Active Customers\", value: 1, trend: \"FLAT\" },",
88
+ " { id: \"report_risk\" as ReportMetric[\"id\"], label: \"At Risk\", value: 1, trend: \"DOWN\" },",
89
+ "];",
90
+ ].join("\n"));
91
+
92
+ writeTextFile(path.join(srcDir, "repositories/user.repository.ts"), [
93
+ "import { usersDb } from \"../database/memoryDb.js\";",
94
+ "import type { User } from \"../types/index.js\";",
95
+ "",
96
+ "export class UserRepository {",
97
+ " async findAll(): Promise<User[]> {",
98
+ " return usersDb.filter(u => !u.deletedAt);",
99
+ " }",
100
+ "",
101
+ " async findByEmail(email: string): Promise<User | null> {",
102
+ " return usersDb.find(u => u.email === email && !u.deletedAt) || null;",
103
+ " }",
104
+ "}",
105
+ ].join("\n"));
106
+
107
+ writeTextFile(path.join(srcDir, "repositories/customer.repository.ts"), [
108
+ "import { customersDb } from \"../database/memoryDb.js\";",
109
+ "import type { Customer } from \"../types/index.js\";",
110
+ "",
111
+ "export class CustomerRepository {",
112
+ " async findAll(): Promise<Customer[]> {",
113
+ " return customersDb.filter(c => !c.deletedAt);",
114
+ " }",
115
+ "}",
116
+ ].join("\n"));
117
+
118
+ writeTextFile(path.join(srcDir, "repositories/role.repository.ts"), [
119
+ "import { rolesDb } from \"../database/memoryDb.js\";",
120
+ "import type { Role } from \"../types/index.js\";",
121
+ "",
122
+ "export class RoleRepository {",
123
+ " async findAll(): Promise<Role[]> {",
124
+ " return rolesDb;",
125
+ " }",
126
+ "}",
127
+ ].join("\n"));
128
+
129
+ writeTextFile(path.join(srcDir, "repositories/report.repository.ts"), [
130
+ "import { reportsDb } from \"../database/memoryDb.js\";",
131
+ "import type { ReportMetric } from \"../types/index.js\";",
132
+ "",
133
+ "export class ReportRepository {",
134
+ " async findAll(): Promise<ReportMetric[]> {",
135
+ " return reportsDb;",
136
+ " }",
137
+ "}",
138
+ ].join("\n"));
139
+
140
+ writeTextFile(path.join(srcDir, "services/dashboard.service.ts"), [
141
+ "import { UserRepository } from \"../repositories/user.repository.js\";",
142
+ "import { CustomerRepository } from \"../repositories/customer.repository.js\";",
143
+ "import { RoleRepository } from \"../repositories/role.repository.js\";",
144
+ "import { ReportRepository } from \"../repositories/report.repository.js\";",
145
+ "import type { DashboardSummary } from \"../types/index.js\";",
146
+ "",
147
+ "export class DashboardService {",
148
+ " private userRepo = new UserRepository();",
149
+ " private customerRepo = new CustomerRepository();",
150
+ " private roleRepo = new RoleRepository();",
151
+ " private reportRepo = new ReportRepository();",
152
+ "",
153
+ " async getSummary(): Promise<DashboardSummary> {",
154
+ " const [users, customers, roles, reports] = await Promise.all([",
155
+ " this.userRepo.findAll(),",
156
+ " this.customerRepo.findAll(),",
157
+ " this.roleRepo.findAll(),",
158
+ " this.reportRepo.findAll(),",
159
+ " ]);",
160
+ "",
161
+ " return { users, customers, roles, reports };",
162
+ " }",
163
+ "}",
164
+ ].join("\n"));
165
+
166
+ writeTextFile(path.join(targetDir, backendDir, "src/server.ts"), [
167
+ "import Fastify from \"fastify\";",
168
+ "import cors from \"@fastify/cors\";",
169
+ "import { z } from \"zod\";",
170
+ "import { UserRepository } from \"./repositories/user.repository.js\";",
171
+ "import { CustomerRepository } from \"./repositories/customer.repository.js\";",
172
+ "import { RoleRepository } from \"./repositories/role.repository.js\";",
173
+ "import { ReportRepository } from \"./repositories/report.repository.js\";",
174
+ "import { DashboardService } from \"./services/dashboard.service.js\";",
175
+ "",
176
+ "const app = Fastify({ logger: true });",
177
+ "await app.register(cors, { origin: true });",
178
+ "",
179
+ "const userRepo = new UserRepository();",
180
+ "const customerRepo = new CustomerRepository();",
181
+ "const roleRepo = new RoleRepository();",
182
+ "const reportRepo = new ReportRepository();",
183
+ "const dashboardService = new DashboardService();",
184
+ "",
185
+ "app.get(\"/health\", async () => ({ ok: true, service: \"agent-enderun-backend\" }));",
186
+ "app.get(\"/api/v1/dashboard\", async () => {",
187
+ " const summary = await dashboardService.getSummary();",
188
+ " return { data: summary };",
189
+ "});",
190
+ "app.get(\"/api/v1/users\", async () => {",
191
+ " const users = await userRepo.findAll();",
192
+ " return { data: users };",
193
+ "});",
194
+ "app.get(\"/api/v1/roles\", async () => {",
195
+ " const roles = await roleRepo.findAll();",
196
+ " return { data: roles };",
197
+ "});",
198
+ "app.get(\"/api/v1/customers\", async () => {",
199
+ " const customers = await customerRepo.findAll();",
200
+ " return { data: customers };",
201
+ "});",
202
+ "app.get(\"/api/v1/reports\", async (request, reply) => {",
203
+ " interface QueryParams {",
204
+ " page?: number;",
205
+ " limit?: number;",
206
+ " }",
207
+ " const { page = 1, limit = 10 } = request.query as QueryParams;",
208
+ " const reports = await reportRepo.findAll();",
209
+ " const startIndex = (Number(page) - 1) * Number(limit);",
210
+ " const endIndex = startIndex + Number(limit);",
211
+ " const paginatedReports = reports.slice(startIndex, endIndex);",
212
+ " reply.send({",
213
+ " data: paginatedReports,",
214
+ " meta: {",
215
+ " total: reports.length,",
216
+ " page: Number(page),",
217
+ " limit: Number(limit),",
218
+ " },",
219
+ " });",
220
+ "});",
221
+ "",
222
+ "app.post(\"/api/v1/auth/login\", async (request, reply) => {",
223
+ " const body = z.object({ email: z.string().email(), password: z.string().min(1) }).safeParse(request.body);",
224
+ " if (!body.success) return reply.code(400).send({ error: { code: \"VALIDATION_ERROR\", message: \"Invalid login payload\" } });",
225
+ "",
226
+ " const user = await userRepo.findByEmail(body.data.email);",
227
+ " if (!user) {",
228
+ " const allUsers = await userRepo.findAll();",
229
+ " return { data: { user: allUsers[0], token: \"demo-token\", expiresAt: new Date(Date.now() + 3600000).toISOString() } };",
230
+ " }",
231
+ " return { data: { user, token: \"demo-token\", expiresAt: new Date(Date.now() + 3600000).toISOString() } };",
232
+ "});",
233
+ "",
234
+ "const port = Number(process.env.PORT || 4000);",
235
+ "await app.listen({ port, host: \"0.0.0.0\" });",
236
+ ].join("\n"));
237
+
238
+ writeTextFile(path.join(targetDir, backendDir, "README.md"), [
239
+ `# ${spec.title} Backend`,
240
+ "",
241
+ "Fastify API generated by Agent Enderun.",
242
+ "",
243
+ "## Commands",
244
+ "",
245
+ "- \`npm run dev\` strings",
246
+ "- \`npm run build\` strings",
247
+ "- \`npm run test\` strings",
248
+ ].join("\n"));
249
+ }
@@ -0,0 +1,65 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { ensureDir, writeTextFile } from "./fs.js";
4
+ import { getConfiguredPaths, getMemoryPath, updateProjectMemory } from "./memory.js";
5
+ import type { AppSpec } from "./app-inferrer.js";
6
+
7
+ const targetDir = process.cwd();
8
+
9
+ export function updateProjectDocs(spec: AppSpec): void {
10
+ const pathsMap = getConfiguredPaths();
11
+ const docsDir = path.join(targetDir, pathsMap.docs);
12
+ const apiDir = path.join(docsDir, "api");
13
+ ensureDir(apiDir);
14
+
15
+ writeTextFile(path.join(docsDir, "project-docs.md"), [
16
+ `# ${spec.title} Requirements`,
17
+ "",
18
+ "## Request",
19
+ "",
20
+ spec.rawDescription,
21
+ "",
22
+ "## Generated Scope",
23
+ "",
24
+ `- Domain: ${spec.domain}`,
25
+ `- Auth: ${spec.modules.auth ? "yes" : "no"}`,
26
+ `- Users: ${spec.modules.users ? "yes" : "no"}`,
27
+ `- Roles: ${spec.modules.roles ? "yes" : "no"}`,
28
+ `- Reports: ${spec.modules.reports ? "yes" : "no"}`,
29
+ "",
30
+ "## Architecture",
31
+ "",
32
+ `- \`${pathsMap.backend}\`: Fastify API`,
33
+ `- \`${pathsMap.frontend}\`: React dashboard`,
34
+ `- \`${pathsMap.backend}/src/types\`: Contract-first backend TypeScript types`,
35
+ ].join("\n"));
36
+
37
+ writeTextFile(path.join(apiDir, "README.md"), [
38
+ "# API Registry",
39
+ "",
40
+ "- `POST /api/v1/auth/login`",
41
+ "- `GET /api/v1/dashboard`",
42
+ "- `GET /api/v1/users`",
43
+ "- `GET /api/v1/roles`",
44
+ "- `GET /api/v1/customers`",
45
+ "- `GET /api/v1/reports`",
46
+ ].join("\n"));
47
+ }
48
+
49
+ export function updateMemoryForGeneratedApp(spec: AppSpec, traceId: string): void {
50
+ const memoryPath = getMemoryPath();
51
+ if (!fs.existsSync(memoryPath)) return;
52
+
53
+ const pathsMap = getConfiguredPaths();
54
+ const today = new Date().toISOString().split("T")[0];
55
+ const history = [
56
+ `### ${today} — Generated ${spec.title}`,
57
+ "",
58
+ "- **Agent:** @manager",
59
+ `- **Trace ID:** ${traceId}`,
60
+ "- **Action:** Created full-stack starter from natural language request.",
61
+ `- **Files:** ${pathsMap.backend}, ${pathsMap.frontend}, project docs`,
62
+ ].join("\n");
63
+
64
+ updateProjectMemory("HISTORY", history);
65
+ }
@@ -0,0 +1,257 @@
1
+ import path from "path";
2
+ import { writeJsonFile, writeTextFile } from "./fs.js";
3
+ import { getConfiguredPaths } from "./memory.js";
4
+ import { getDependencyVersions } from "./pkg.js";
5
+ import { createBaseTypeFiles } from "./app-types.js";
6
+ import type { AppSpec } from "./app-inferrer.js";
7
+
8
+ const targetDir = process.cwd();
9
+
10
+ export function createWebFiles(spec: AppSpec): void {
11
+ const pathsMap = getConfiguredPaths();
12
+ const frontendDir = pathsMap.frontend;
13
+ const { "@vitejs/plugin-react": vitePluginReact, vite, react, "react-dom": reactDom, "lucide-react": lucideReact, "@types/react": typesReact, "@types/react-dom": typesReactDom, typescript, "vitest-frontend": vitest } = getDependencyVersions();
14
+
15
+ createBaseTypeFiles(path.join(targetDir, frontendDir, "src"));
16
+ writeJsonFile(path.join(targetDir, frontendDir, "package.json"), {
17
+ name: "@agent-enderun/web",
18
+ version: "0.1.0",
19
+ private: true,
20
+ type: "module",
21
+ scripts: {
22
+ dev: "vite --host 0.0.0.0",
23
+ build: "tsc -p tsconfig.json && vite build",
24
+ preview: "vite preview",
25
+ test: "vitest run",
26
+ },
27
+ dependencies: {
28
+ "@vitejs/plugin-react": vitePluginReact,
29
+ vite: vite,
30
+ react: react,
31
+ "react-dom": reactDom,
32
+ "lucide-react": lucideReact,
33
+ },
34
+ devDependencies: {
35
+ "@types/react": typesReact,
36
+ "@types/react-dom": typesReactDom,
37
+ typescript: typescript,
38
+ vitest: vitest,
39
+ },
40
+ });
41
+
42
+ writeJsonFile(path.join(targetDir, frontendDir, "tsconfig.json"), {
43
+ extends: "../../tsconfig.json",
44
+ compilerOptions: {
45
+ jsx: "react-jsx",
46
+ module: "NodeNext",
47
+ moduleResolution: "NodeNext",
48
+ target: "ES2022",
49
+ strict: true,
50
+ skipLibCheck: true,
51
+ },
52
+ include: ["src/**/*.ts", "src/**/*.tsx"],
53
+ });
54
+
55
+ writeTextFile(path.join(targetDir, frontendDir, "index.html"), [
56
+ "<div id=\"root\"></div>",
57
+ "<script type=\"module\" src=\"/src/main.tsx\"></script>",
58
+ ].join("\n"));
59
+
60
+ writeTextFile(path.join(targetDir, frontendDir, "src/main.tsx"), [
61
+ "import React from \"react\";",
62
+ "import { createRoot } from \"react-dom/client\";",
63
+ "import { App } from \"./App.js\";",
64
+ "import \"./styles.css\";",
65
+ "",
66
+ "createRoot(document.getElementById(\"root\") as HTMLElement).render(",
67
+ " <React.StrictMode>",
68
+ " <App />",
69
+ " </React.StrictMode>,",
70
+ ");",
71
+ ].join("\n"));
72
+
73
+ writeTextFile(path.join(targetDir, frontendDir, "src/App.tsx"), [
74
+ "import { BarChart3, ShieldCheck, UsersRound } from \"lucide-react\";",
75
+ "",
76
+ "const metrics = [",
77
+ " { label: \"Pipeline\", value: \"$261K\", tone: \"green\" },",
78
+ " { label: \"Active customers\", value: \"18\", tone: \"blue\" },",
79
+ " { label: \"At risk\", value: \"3\", tone: \"red\" },",
80
+ "];",
81
+ "",
82
+ "const customers = [",
83
+ " { name: \"Northwind\", status: \"Active\", owner: \"Sales Manager\", value: \"$125K\" },",
84
+ " { name: \"Acme Corp\", status: \"Lead\", owner: \"Sales Manager\", value: \"$82K\" },",
85
+ " { name: \"Globex\", status: \"At risk\", owner: \"Admin User\", value: \"$54K\" },",
86
+ "];",
87
+ "",
88
+ "export function App() {",
89
+ " return (",
90
+ " <main className=\"shell\">",
91
+ " <aside className=\"sidebar\" aria-label=\"Primary navigation\">",
92
+ " <div className=\"brand\">AE</div>",
93
+ " <nav>",
94
+ " <a className=\"active\" href=\"#dashboard\"><BarChart3 size={18} /> Dashboard</a>",
95
+ " <a href=\"#users\"><UsersRound size={18} /> Users</a>",
96
+ " <a href=\"#roles\"><ShieldCheck size={18} /> Roles</a>",
97
+ " </nav>",
98
+ " </aside>",
99
+ "",
100
+ " <section className=\"workspace\">",
101
+ " <header className=\"topbar\">",
102
+ " <div>",
103
+ " <p>{spec.domain}</p>",
104
+ " <h1>{spec.title}</h1>",
105
+ " </div>",
106
+ " <button type=\"button\">New customer</button>",
107
+ " </header>",
108
+ "",
109
+ " <section className=\"metrics\" aria-label=\"Report metrics\">",
110
+ " {metrics.map((metric) => (",
111
+ " <article className={`metric ${metric.tone}`} key={metric.label}>",
112
+ " <span>{metric.label}</span>",
113
+ " <strong>{metric.value}</strong>",
114
+ " </article>",
115
+ " ))}",
116
+ " </section>",
117
+ "",
118
+ " <section className=\"panel\">",
119
+ " <div>",
120
+ " <h2>Customers</h2>",
121
+ " <p>Ownership, value and status at a glance.</p>",
122
+ " </div>",
123
+ " <div className=\"table\">",
124
+ " {customers.map((customer) => (",
125
+ " <div className=\"row\" key={customer.name}>",
126
+ " <strong>{customer.name}</strong>",
127
+ " <span>{customer.status}</span>",
128
+ " <span>{customer.owner}</span>",
129
+ " <b>{customer.value}</b>",
130
+ " </div>",
131
+ " ))}",
132
+ " </div>",
133
+ " </section>",
134
+ " </section>",
135
+ " </main>",
136
+ " );",
137
+ "}",
138
+ ].join("\n"));
139
+
140
+ writeTextFile(path.join(targetDir, frontendDir, "src/styles.css"), [
141
+ ":root {",
142
+ " color: #172026;",
143
+ " background: #f4f7f6;",
144
+ " font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;",
145
+ "}",
146
+ "",
147
+ "* { box-sizing: border-box; }",
148
+ "body { margin: 0; }",
149
+ "button { font: inherit; }",
150
+ "",
151
+ ".shell {",
152
+ " min-height: 100vh;",
153
+ " display: grid;",
154
+ " grid-template-columns: 240px 1fr;",
155
+ "}",
156
+ "",
157
+ ".sidebar {",
158
+ " background: #102022;",
159
+ " color: #eef6f2;",
160
+ " padding: 24px;",
161
+ "}",
162
+ "",
163
+ ".brand {",
164
+ " width: 40px;",
165
+ " height: 40px;",
166
+ " display: grid;",
167
+ " place-items: center;",
168
+ " background: #d8f36a;",
169
+ " color: #102022;",
170
+ " font-weight: 800;",
171
+ " border-radius: 8px;",
172
+ " margin-bottom: 32px;",
173
+ "}",
174
+ "",
175
+ "nav { display: grid; gap: 8px; }",
176
+ "nav a {",
177
+ " color: inherit;",
178
+ " text-decoration: none;",
179
+ " display: flex;",
180
+ " gap: 10px;",
181
+ " align-items: center;",
182
+ " padding: 10px 12px;",
183
+ " border-radius: 8px;",
184
+ "}",
185
+ "nav a.active, nav a:hover { background: rgba(255,255,255,0.12); }",
186
+ "",
187
+ ".workspace { padding: 32px; }",
188
+ ".topbar {",
189
+ " display: flex;",
190
+ " justify-content: space-between;",
191
+ " align-items: center;",
192
+ " gap: 24px;",
193
+ " margin-bottom: 24px;",
194
+ "}",
195
+ ".topbar p { margin: 0 0 4px; color: #58666a; font-size: 14px; }",
196
+ ".topbar h1 { margin: 0; font-size: 32px; letter-spacing: 0; }",
197
+ ".topbar button {",
198
+ " border: 0;",
199
+ " border-radius: 8px;",
200
+ " background: #176b5d;",
201
+ " color: white;",
202
+ " padding: 10px 14px;",
203
+ "}",
204
+ "",
205
+ ".metrics {",
206
+ " display: grid;",
207
+ " grid-template-columns: repeat(3, minmax(0, 1fr));",
208
+ " gap: 16px;",
209
+ " margin-bottom: 24px;",
210
+ "}",
211
+ ".metric, .panel {",
212
+ " background: white;",
213
+ " border: 1px solid #d9e3e0;",
214
+ " border-radius: 8px;",
215
+ "}",
216
+ ".metric { padding: 18px; }",
217
+ ".metric span { display: block; color: #58666a; margin-bottom: 8px; }",
218
+ ".metric strong { font-size: 28px; }",
219
+ ".metric.green { border-top: 4px solid #49a078; }",
220
+ ".metric.blue { border-top: 4px solid #3f7cac; }",
221
+ ".metric.red { border-top: 4px solid #d95d39; }",
222
+ "",
223
+ ".panel { padding: 20px; }",
224
+ ".panel h2 { margin: 0 0 4px; font-size: 20px; }",
225
+ ".panel p { margin: 0 0 18px; color: #58666a; }",
226
+ ".table { display: grid; gap: 8px; }",
227
+ ".row {",
228
+ " display: grid;",
229
+ " grid-template-columns: 1.4fr 0.8fr 1fr 0.6fr;",
230
+ " gap: 16px;",
231
+ " align-items: center;",
232
+ " padding: 12px;",
233
+ " border-radius: 8px;",
234
+ " background: #f7faf9;",
235
+ "}",
236
+ "",
237
+ "@media (max-width: 760px) {",
238
+ " .shell { grid-template-columns: 1fr; }",
239
+ " .sidebar { position: static; }",
240
+ " .metrics { grid-template-columns: 1fr; }",
241
+ " .topbar { align-items: flex-start; flex-direction: column; }",
242
+ " .row { grid-template-columns: 1fr; }",
243
+ "}",
244
+ ].join("\n"));
245
+
246
+ writeTextFile(path.join(targetDir, frontendDir, "README.md"), [
247
+ `# ${spec.title} Web`,
248
+ "",
249
+ "React dashboard generated by Agent Enderun.",
250
+ "",
251
+ "## Commands",
252
+ "",
253
+ "- \`npm run dev\` strings",
254
+ "- \`npm run build\` strings",
255
+ "- \`npm run test\` strings",
256
+ ].join("\n"));
257
+ }
@@ -0,0 +1,53 @@
1
+ import { slugifyName, titleCase } from "./string.js";
2
+
3
+ export interface AppSpec {
4
+ rawDescription: string;
5
+ appName: string;
6
+ title: string;
7
+ domain: string;
8
+ modules: {
9
+ auth: boolean;
10
+ users: boolean;
11
+ roles: boolean;
12
+ reports: boolean;
13
+ };
14
+ }
15
+
16
+ export function inferAppSpec(description: string): AppSpec {
17
+ const normalized = String(description || "").toLowerCase();
18
+ const isCrm = /\bcrm\b|customer|musteri|müşteri/.test(normalized);
19
+ const hasAuth = /auth|login|giris|giriş|signin|sign in|user|kullanici|kullanıcı|role|rol/.test(normalized);
20
+ const hasRoles = /role|rol|permission|yetki|admin/.test(normalized);
21
+ const hasReports = /report|rapor|analytics|dashboard|chart|metric/.test(normalized);
22
+ const appName = isCrm ? "crm-dashboard" : slugifyName(description).split("-").slice(0, 4).join("-");
23
+
24
+ return {
25
+ rawDescription: description,
26
+ appName,
27
+ title: isCrm ? "CRM Dashboard" : titleCase(appName),
28
+ domain: isCrm ? "CRM" : "Business",
29
+ modules: {
30
+ auth: hasAuth || isCrm,
31
+ users: hasAuth || hasRoles || isCrm,
32
+ roles: hasRoles || isCrm,
33
+ reports: hasReports || isCrm,
34
+ },
35
+ };
36
+ }
37
+
38
+ export async function collectCreateAppDescription(args: string[]): Promise<string> {
39
+ const initial = args.join(" ").trim();
40
+ if (initial) return initial;
41
+
42
+ const readline = await import("readline/promises");
43
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
44
+ try {
45
+ const idea = await rl.question("What do you want to build? ");
46
+ const platform = await rl.question("Platform? (full-stack/web/backend) ");
47
+ const auth = await rl.question("Auth and roles? (yes/no) ");
48
+ const reports = await rl.question("Reports/dashboard? (yes/no) ");
49
+ return [idea, platform, auth.includes("y") ? "with auth and roles" : "", reports.includes("y") ? "with reports dashboard" : ""].filter(Boolean).join(" ");
50
+ } finally {
51
+ rl.close();
52
+ }
53
+ }