imlil 1.0.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 (175) hide show
  1. package/.eslintrc.cjs +40 -0
  2. package/DOCS.md +63 -0
  3. package/README.md +160 -0
  4. package/agentTestSandbox/cli-test-zone/README.md +0 -0
  5. package/agentTestSandbox/cli-test-zone/imlil.blueprint.json +5 -0
  6. package/agentTestSandbox/cli-test-zone/notes-warning.md +3 -0
  7. package/agentTestSandbox/cli-test-zone/package.json +0 -0
  8. package/agentTestSandbox/cli-test-zone/public/index.html +0 -0
  9. package/agentTestSandbox/cli-test-zone/src/App.js +0 -0
  10. package/agentTestSandbox/cli-test-zone/src/App.jsx +29 -0
  11. package/agentTestSandbox/cli-test-zone/src/__tests__/App.test.jsx +48 -0
  12. package/agentTestSandbox/cli-test-zone/src/components/AddTodo.js +0 -0
  13. package/agentTestSandbox/cli-test-zone/src/components/Navigation/Navigation.jsx +48 -0
  14. package/agentTestSandbox/cli-test-zone/src/components/Navigation/__tests__/Navigation.module.test.js +45 -0
  15. package/agentTestSandbox/cli-test-zone/src/components/Navigation/__tests__/Navigation.test.jsx +47 -0
  16. package/agentTestSandbox/cli-test-zone/src/components/Navigation.js +0 -0
  17. package/agentTestSandbox/cli-test-zone/src/components/TodoItem/TodoItem.jsx +41 -0
  18. package/agentTestSandbox/cli-test-zone/src/components/TodoItem/__tests__/TodoItem.test.jsx +65 -0
  19. package/agentTestSandbox/cli-test-zone/src/components/TodoItem.js +0 -0
  20. package/agentTestSandbox/cli-test-zone/src/components/TodoList/TodoList.module.css +62 -0
  21. package/agentTestSandbox/cli-test-zone/src/components/TodoList.js +0 -0
  22. package/agentTestSandbox/cli-test-zone/src/index.js +0 -0
  23. package/agentTestSandbox/cli-test-zone/src/pages/About.js +0 -0
  24. package/agentTestSandbox/cli-test-zone/src/pages/Home.js +0 -0
  25. package/agentTestSandbox/cli-test-zone/src/store/TodoContext.js +0 -0
  26. package/agentTestSandbox/cli-test-zone/src/styles/Todo.css +0 -0
  27. package/agentTestSandbox/cli-test-zone/src/styles/index.css +0 -0
  28. package/agentTestSandbox/cli-test-zone/src/utils/__tests__/localStorage.test.js +48 -0
  29. package/agentTestSandbox/cli-test-zone/src/utils/localStorage.js +38 -0
  30. package/agentTestSandbox/parallel-test/.env.example +0 -0
  31. package/agentTestSandbox/parallel-test/.eslintrc.json +0 -0
  32. package/agentTestSandbox/parallel-test/.github/workflows/__tests__/workflows.test.ts +115 -0
  33. package/agentTestSandbox/parallel-test/.github/workflows/cd.yml +0 -0
  34. package/agentTestSandbox/parallel-test/.github/workflows/ci.yml +4 -0
  35. package/agentTestSandbox/parallel-test/.imlil/plan-2026-02-08.md +186 -0
  36. package/agentTestSandbox/parallel-test/.prettierrc +0 -0
  37. package/agentTestSandbox/parallel-test/Dockerfile +0 -0
  38. package/agentTestSandbox/parallel-test/README.md +3 -0
  39. package/agentTestSandbox/parallel-test/ast.json +74 -0
  40. package/agentTestSandbox/parallel-test/docker-compose.yml +4 -0
  41. package/agentTestSandbox/parallel-test/jest.config.js +61 -0
  42. package/agentTestSandbox/parallel-test/k8s/__tests__/deployment.test.ts +168 -0
  43. package/agentTestSandbox/parallel-test/k8s/frontend-deployment.yaml +4 -0
  44. package/agentTestSandbox/parallel-test/nginx/nginx.conf +0 -0
  45. package/agentTestSandbox/parallel-test/package.json +50 -0
  46. package/agentTestSandbox/parallel-test/prisma/__tests__/schema.test.ts +176 -0
  47. package/agentTestSandbox/parallel-test/prisma/schema.prisma +109 -0
  48. package/agentTestSandbox/parallel-test/server/__tests__/controllers/dashboard.controller.test.ts +127 -0
  49. package/agentTestSandbox/parallel-test/server/__tests__/index.test.ts +60 -0
  50. package/agentTestSandbox/parallel-test/server/__tests__/models/user.model.test.ts +111 -0
  51. package/agentTestSandbox/parallel-test/server/config/__tests__/swagger.test.ts +128 -0
  52. package/agentTestSandbox/parallel-test/server/config/database.ts +0 -0
  53. package/agentTestSandbox/parallel-test/server/config/redis.ts +0 -0
  54. package/agentTestSandbox/parallel-test/server/config/swagger.ts +0 -0
  55. package/agentTestSandbox/parallel-test/server/controllers/__tests__/auth.controller.test.ts +178 -0
  56. package/agentTestSandbox/parallel-test/server/controllers/__tests__/user.controller.test.ts +105 -0
  57. package/agentTestSandbox/parallel-test/server/controllers/auth.controller.ts +148 -0
  58. package/agentTestSandbox/parallel-test/server/controllers/dashboard.controller.ts +137 -0
  59. package/agentTestSandbox/parallel-test/server/controllers/user.controller.ts +161 -0
  60. package/agentTestSandbox/parallel-test/server/index.ts +62 -0
  61. package/agentTestSandbox/parallel-test/server/middleware/__tests__/auth.middleware.test.ts +74 -0
  62. package/agentTestSandbox/parallel-test/server/middleware/auth.middleware.ts +55 -0
  63. package/agentTestSandbox/parallel-test/server/middleware/error.middleware.ts +0 -0
  64. package/agentTestSandbox/parallel-test/server/middleware/validation.middleware.ts +0 -0
  65. package/agentTestSandbox/parallel-test/server/models/analytics.model.ts +0 -0
  66. package/agentTestSandbox/parallel-test/server/models/profile.model.ts +0 -0
  67. package/agentTestSandbox/parallel-test/server/models/user.model.ts +78 -0
  68. package/agentTestSandbox/parallel-test/server/routes/auth.routes.ts +0 -0
  69. package/agentTestSandbox/parallel-test/server/routes/dashboard.routes.ts +0 -0
  70. package/agentTestSandbox/parallel-test/server/routes/user.routes.ts +0 -0
  71. package/agentTestSandbox/parallel-test/src/App.tsx +0 -0
  72. package/agentTestSandbox/parallel-test/src/__tests__/config.test.ts +127 -0
  73. package/agentTestSandbox/parallel-test/src/__tests__/index.test.tsx +36 -0
  74. package/agentTestSandbox/parallel-test/src/__tests__/setup.test.ts +34 -0
  75. package/agentTestSandbox/parallel-test/src/__tests__/setupTest.test.ts +44 -0
  76. package/agentTestSandbox/parallel-test/src/components/common/Button/Button.tsx +80 -0
  77. package/agentTestSandbox/parallel-test/src/components/common/Button/__tests__/Button.test.tsx +75 -0
  78. package/agentTestSandbox/parallel-test/src/components/common/Card/Card.tsx +0 -0
  79. package/agentTestSandbox/parallel-test/src/components/common/Input/Input.tsx +0 -0
  80. package/agentTestSandbox/parallel-test/src/components/common/Table/Table.tsx +0 -0
  81. package/agentTestSandbox/parallel-test/src/components/features/Authentication/LoginForm.tsx +75 -0
  82. package/agentTestSandbox/parallel-test/src/components/features/Authentication/RegisterForm.tsx +0 -0
  83. package/agentTestSandbox/parallel-test/src/components/features/Authentication/__tests__/LoginForm.test.tsx +101 -0
  84. package/agentTestSandbox/parallel-test/src/components/features/Dashboard/AnalyticsChart.tsx +0 -0
  85. package/agentTestSandbox/parallel-test/src/components/features/Dashboard/DashboardStats.tsx +81 -0
  86. package/agentTestSandbox/parallel-test/src/components/features/Dashboard/__tests__/DashboardStats.test.tsx +122 -0
  87. package/agentTestSandbox/parallel-test/src/components/layouts/Header.tsx +70 -0
  88. package/agentTestSandbox/parallel-test/src/components/layouts/MainLayout.tsx +0 -0
  89. package/agentTestSandbox/parallel-test/src/components/layouts/Sidebar.tsx +0 -0
  90. package/agentTestSandbox/parallel-test/src/components/layouts/__tests__/MainLayout.test.tsx +65 -0
  91. package/agentTestSandbox/parallel-test/src/hooks/__tests__/useAuth.test.ts +75 -0
  92. package/agentTestSandbox/parallel-test/src/hooks/useApi.ts +0 -0
  93. package/agentTestSandbox/parallel-test/src/hooks/useAuth.ts +54 -0
  94. package/agentTestSandbox/parallel-test/src/hooks/useTheme.ts +0 -0
  95. package/agentTestSandbox/parallel-test/src/index.tsx +0 -0
  96. package/agentTestSandbox/parallel-test/src/services/__tests__/api.service.test.ts +48 -0
  97. package/agentTestSandbox/parallel-test/src/services/analytics.service.ts +0 -0
  98. package/agentTestSandbox/parallel-test/src/services/api.service.ts +59 -0
  99. package/agentTestSandbox/parallel-test/src/services/api.ts +0 -0
  100. package/agentTestSandbox/parallel-test/src/services/auth.service.ts +0 -0
  101. package/agentTestSandbox/parallel-test/src/services/user.service.ts +0 -0
  102. package/agentTestSandbox/parallel-test/src/store/__tests__/store.test.ts +60 -0
  103. package/agentTestSandbox/parallel-test/src/store/index.ts +23 -0
  104. package/agentTestSandbox/parallel-test/src/store/slices/authSlice.ts +0 -0
  105. package/agentTestSandbox/parallel-test/src/store/slices/dashboardSlice.ts +0 -0
  106. package/agentTestSandbox/parallel-test/src/store/slices/userSlice.ts +0 -0
  107. package/agentTestSandbox/parallel-test/src/types/auth.types.ts +0 -0
  108. package/agentTestSandbox/parallel-test/src/types/dashboard.types.ts +0 -0
  109. package/agentTestSandbox/parallel-test/src/types/user.types.ts +0 -0
  110. package/agentTestSandbox/parallel-test/src/utils/constants.ts +0 -0
  111. package/agentTestSandbox/parallel-test/src/utils/formatters.ts +0 -0
  112. package/agentTestSandbox/parallel-test/src/utils/validation.ts +0 -0
  113. package/agentTestSandbox/parallel-test/src/views/Dashboard.tsx +0 -0
  114. package/agentTestSandbox/parallel-test/src/views/Login.tsx +31 -0
  115. package/agentTestSandbox/parallel-test/src/views/Profile.tsx +0 -0
  116. package/agentTestSandbox/parallel-test/src/views/Register.tsx +0 -0
  117. package/agentTestSandbox/parallel-test/src/views/Settings.tsx +0 -0
  118. package/agentTestSandbox/parallel-test/src/views/__tests__/Login.test.tsx +62 -0
  119. package/agentTestSandbox/parallel-test/src/vite-env.d.ts +1 -0
  120. package/agentTestSandbox/parallel-test/tailwind.config.js +0 -0
  121. package/agentTestSandbox/parallel-test/tests/integration/api/auth.test.ts +120 -0
  122. package/agentTestSandbox/parallel-test/tests/unit/components/Button.test.tsx +35 -0
  123. package/agentTestSandbox/parallel-test/tests/unit/config/jest.config.test.js +62 -0
  124. package/agentTestSandbox/parallel-test/tests/unit/config/jest.setup.test.js +52 -0
  125. package/agentTestSandbox/parallel-test/tests/unit/infrastructure/__tests__/docker-config.test.ts +107 -0
  126. package/agentTestSandbox/parallel-test/tsconfig.json +0 -0
  127. package/agentTestSandbox/zone2/Makefile +58 -0
  128. package/agentTestSandbox/zone2/README.md +0 -0
  129. package/agentTestSandbox/zone2/docs/API.md +0 -0
  130. package/agentTestSandbox/zone2/docs/CONTRIBUTING.md +0 -0
  131. package/agentTestSandbox/zone2/imlil.blueprint.json +5 -0
  132. package/agentTestSandbox/zone2/notes-warning.md +3 -0
  133. package/agentTestSandbox/zone2/src/calculator.c +0 -0
  134. package/agentTestSandbox/zone2/src/calculator.h +0 -0
  135. package/agentTestSandbox/zone2/src/core/__tests__/test_memory.c +89 -0
  136. package/agentTestSandbox/zone2/src/core/memory.c +60 -0
  137. package/agentTestSandbox/zone2/src/display.c +0 -0
  138. package/agentTestSandbox/zone2/src/display.h +0 -0
  139. package/agentTestSandbox/zone2/src/input_handler.c +0 -0
  140. package/agentTestSandbox/zone2/src/input_handler.h +0 -0
  141. package/agentTestSandbox/zone2/src/main.c +0 -0
  142. package/agentTestSandbox/zone2/src/utils/error_handling.c +0 -0
  143. package/agentTestSandbox/zone2/src/utils/error_handling.h +0 -0
  144. package/agentTestSandbox/zone2/src/utils/input.c +0 -0
  145. package/agentTestSandbox/zone2/src/utils/input.h +0 -0
  146. package/agentTestSandbox/zone2/src/utils/math_utils.c +0 -0
  147. package/agentTestSandbox/zone2/src/utils/math_utils.h +0 -0
  148. package/agentTestSandbox/zone2/src/utils/stack.c +0 -0
  149. package/agentTestSandbox/zone2/src/utils/stack.h +0 -0
  150. package/agentTestSandbox/zone2/src/utils.c +34 -0
  151. package/agentTestSandbox/zone2/tests/__tests__/test_makefile.c +58 -0
  152. package/agentTestSandbox/zone2/tests/calculator_tests.c +0 -0
  153. package/agentTestSandbox/zone2/tests/input_handler_tests.c +0 -0
  154. package/agentTestSandbox/zone2/tests/math_utils_tests.c +0 -0
  155. package/agentTestSandbox/zone2/tests/test_calculator.c +0 -0
  156. package/agentTestSandbox/zone2/tests/test_input.c +0 -0
  157. package/agentTestSandbox/zone2/tests/test_stack.c +0 -0
  158. package/agentTestSandbox/zone2/tests/test_utils.c +8 -0
  159. package/bin/cli.js +369 -0
  160. package/imlil.config.js +22 -0
  161. package/index.js +0 -0
  162. package/jest.config.js +5 -0
  163. package/package.json +45 -0
  164. package/src/__tests__/cli.test.js +5 -0
  165. package/src/actions/Action.js +125 -0
  166. package/src/agents/Agent.js +64 -0
  167. package/src/agents/Operator.js +147 -0
  168. package/src/agents/ScrumAgent.js +74 -0
  169. package/src/agents/SupervisorAgent.js +198 -0
  170. package/src/agents/ValidatorAgent.js +48 -0
  171. package/src/agents/coder.js +208 -0
  172. package/src/agents/worker.js +52 -0
  173. package/src/utils/db.js +40 -0
  174. package/src/utils/embedapi.js +19 -0
  175. package/test-api.js +24 -0
@@ -0,0 +1,125 @@
1
+ import glob from 'fast-glob';
2
+ import { promises as fs } from 'fs';
3
+ import esprima from 'esprima';
4
+ import recast from 'recast';
5
+ import simpleGit from 'simple-git';
6
+ import path from 'path';
7
+ import jscodeshift from 'jscodeshift';
8
+ import Parser from 'tree-sitter';
9
+ import JavaScript from 'tree-sitter-javascript';
10
+
11
+ export default class Action {
12
+ constructor() {
13
+ this.git = simpleGit();
14
+ this.parser = new Parser();
15
+ this.parser.setLanguage(JavaScript);
16
+ }
17
+
18
+ static async findFiles(pattern) {
19
+ return glob(pattern);
20
+ }
21
+
22
+ static async readFile(filePath) {
23
+ return fs.readFile(filePath, 'utf-8');
24
+ }
25
+
26
+ static async writeFile(filePath, content) {
27
+ if (!filePath) {
28
+ console.error('Error: filePath is undefined');
29
+ return;
30
+ }
31
+ console.log(` => Writing file: ${filePath}`);
32
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
33
+ const contentToWrite = typeof content === 'string' ? content : JSON.stringify(content, null, 4);
34
+ await fs.writeFile(filePath, contentToWrite);
35
+ }
36
+
37
+ static async writeTest(filePath, content) {
38
+ if (!filePath) {
39
+ console.error('Error: test filePath is undefined');
40
+ return;
41
+ }
42
+ console.log(` => Writing test: ${filePath}`);
43
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
44
+ const contentToWrite = typeof content === 'string' ? content : JSON.stringify(content, null, 4);
45
+ await fs.writeFile(filePath, contentToWrite);
46
+ }
47
+
48
+ /**
49
+ * Query a file using Tree-sitter for fast structural analysis.
50
+ */
51
+ async queryFile(filePath, queryStr) {
52
+ const source = await fs.readFile(filePath, 'utf-8');
53
+ const tree = this.parser.parse(source);
54
+ const query = new Parser.Query(JavaScript, queryStr);
55
+ const matches = query.matches(tree.rootNode);
56
+ return matches;
57
+ }
58
+
59
+ /**
60
+ * Surgical modification using jscodeshift and recast.
61
+ */
62
+ static async modifyFile(filePath, transformCode) {
63
+ if (!filePath) {
64
+ console.error('Error: filePath is undefined for modification');
65
+ return;
66
+ }
67
+ console.log(` => Modifying file: ${filePath}`);
68
+
69
+ let source;
70
+ try {
71
+ source = await fs.readFile(filePath, 'utf-8');
72
+ } catch (e) {
73
+ console.error(`Error reading file ${filePath}:`, e);
74
+ return;
75
+ }
76
+
77
+ const j = jscodeshift.withParser('tsx');
78
+ const api = { j, jscodeshift: j, stats: () => {} };
79
+ const fileInfo = { path: filePath, source };
80
+
81
+ try {
82
+ const result = j.runTransform({ path: filePath, source: fileInfo.source }, transformCode, api, {});
83
+
84
+ if (result && typeof result === 'string' && result !== source) {
85
+ await fs.writeFile(filePath, result);
86
+ console.log(` => File modified successfully: ${filePath}`);
87
+ } else {
88
+ console.log(` => No changes applied to: ${filePath}`);
89
+ }
90
+ } catch (error) {
91
+ console.error(`Error executing jscodeshift transform on ${filePath}:`, error);
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Specialized action for adding imports or surgical edits using AST.
97
+ */
98
+ static async smartEdit(filePath, editInstructions) {
99
+ // This combines tree-sitter for finding and jscodeshift for editing.
100
+ // For now, it will be an alias to modifyFile but with a more specialized prompt context.
101
+ return Action.modifyFile(filePath, editInstructions);
102
+ }
103
+
104
+ static parseCode(code) {
105
+ return esprima.parseScript(code, { tolerant: true, range: true, loc: true });
106
+ }
107
+
108
+ static modifyCode(code, transformations) {
109
+ const ast = recast.parse(code);
110
+ recast.visit(ast, transformations);
111
+ return recast.print(ast).code;
112
+ }
113
+
114
+ async gitStatus() {
115
+ return this.git.status();
116
+ }
117
+
118
+ async gitAdd(files) {
119
+ return this.git.add(files);
120
+ }
121
+
122
+ async gitCommit(message) {
123
+ return this.git.commit(message);
124
+ }
125
+ }
@@ -0,0 +1,64 @@
1
+ class Agent {
2
+ constructor(name, purpose) {
3
+ this.id = Agent.generateId();
4
+ this.name = name;
5
+ this.purpose = purpose;
6
+ this.state = 'idle'; // idle, init, working, stopped
7
+ this.progress = 0;
8
+ this.result = null;
9
+ this.error = null;
10
+ this.intervalId = null;
11
+ }
12
+
13
+ static generateId() {
14
+ return Math.random().toString(36).substr(2, 9);
15
+ }
16
+
17
+ // Initialize the agent
18
+ init() {
19
+ if (this.state !== 'idle') {
20
+ throw new Error('Agent must be idle to initialize');
21
+ }
22
+ this.state = 'init';
23
+ this.progress = 0;
24
+ this.result = null;
25
+ this.error = null;
26
+ }
27
+
28
+ // Start the agent's work
29
+ start(interval = 1000) {
30
+ if (this.state !== 'init') {
31
+ throw new Error('Agent must be initialized to start');
32
+ }
33
+ this.state = 'working';
34
+ this.intervalId = setInterval(() => this.execute(), interval);
35
+ }
36
+
37
+ // Stop the agent
38
+ stop() {
39
+ if (this.intervalId) {
40
+ clearInterval(this.intervalId);
41
+ this.intervalId = null;
42
+ }
43
+ this.state = 'stopped';
44
+ }
45
+
46
+ // Execute the agent's purpose (to be implemented by specific agents)
47
+ // eslint-disable-next-line class-methods-use-this
48
+ execute() {
49
+ throw new Error('Abstract method execute() must be implemented by subclass');
50
+ }
51
+
52
+ // Get the current state of the agent
53
+ getStatus() {
54
+ return {
55
+ name: this.name,
56
+ state: this.state,
57
+ progress: this.progress,
58
+ result: this.result,
59
+ error: this.error,
60
+ };
61
+ }
62
+ }
63
+
64
+ export default Agent;
@@ -0,0 +1,147 @@
1
+ import Agent from './Agent.js';
2
+ import callEmbedApi from '../utils/embedapi.js';
3
+ import { getDb } from '../utils/db.js';
4
+
5
+ class Operator extends Agent {
6
+ constructor(name, purpose, aiModel, apiKey) {
7
+ super(name, purpose);
8
+ this.aiModel = aiModel;
9
+ this.apiKey = apiKey;
10
+ this.db = getDb();
11
+ this.currentTask = null;
12
+ }
13
+
14
+ async generateStructure(objective) {
15
+ console.log(`Operator designing file structure for: ${objective}`);
16
+ const structurePrompt = `
17
+ **CRITICAL: YOUR RESPONSE MUST BE A VALID JSON OBJECT AND NOTHING ELSE.**
18
+
19
+ Based on the objective: "${objective}", design a file structure for the project.
20
+ Return a JSON object where keys are file paths (relative to root) and values are brief descriptions of content (or null for empty files).
21
+ Directories are implied by the paths.
22
+
23
+ Example:
24
+ {
25
+ "src/index.js": "Entry point",
26
+ "src/components/Header.js": "Header component",
27
+ "src/utils/helpers.js": "Helper functions",
28
+ "package.json": "Project manifest"
29
+ }
30
+ `;
31
+
32
+ const response = await callEmbedApi(structurePrompt, this.apiKey);
33
+ try {
34
+ let parsableJson;
35
+ if (response.trim().startsWith('{')) {
36
+ const startIndex = response.indexOf('{');
37
+ const endIndex = response.lastIndexOf('}');
38
+ parsableJson = response.substring(startIndex, endIndex + 1);
39
+ } else {
40
+ throw new Error('Response is not a JSON object');
41
+ }
42
+ return JSON.parse(parsableJson);
43
+ } catch (error) {
44
+ console.error('Error parsing structure JSON:', error);
45
+ return {}; // Fallback to empty if failed
46
+ }
47
+ }
48
+
49
+ async run(objective) {
50
+ console.log(`Operator planning for objective: ${objective}`);
51
+ const planningPrompt = `
52
+ **CRITICAL: YOUR RESPONSE MUST BE A VALID JSON OBJECT AND NOTHING ELSE.**
53
+
54
+ Generate a project plan for the objective: "${objective}".
55
+
56
+ **ARCHITECTURAL REQUIREMENT: MAXIMUM PARALLELISM**
57
+ - The goal is to have multiple agents working at the same time.
58
+ - **Minimize dependencies.** Only use dependencies when strictly necessary.
59
+ - Break the project into independent components/modules.
60
+
61
+ **REQUIRED JSON STRUCTURE:**
62
+ {
63
+ "blueprint": {
64
+ "fileStructure": "Description of the directory structure (e.g., src/components, src/utils)",
65
+ "conventions": "Naming conventions (e.g., PascalCase for components), testing conventions (e.g., place tests in __tests__ folder)",
66
+ "techStack": "List of key technologies (e.g., React, Jest, CSS Modules)"
67
+ },
68
+ "tasks": [
69
+ {
70
+ "id": 1,
71
+ "title": "Task Title",
72
+ "description": "Task Description",
73
+ "status": "pending",
74
+ "dependencies": []
75
+ }
76
+ ]
77
+ }
78
+ `;
79
+ const planJson = await callEmbedApi(planningPrompt, this.apiKey);
80
+ if (planJson) {
81
+ try {
82
+ let parsableJson;
83
+ if (planJson.trim().startsWith('{')) {
84
+ const startIndex = planJson.indexOf('{');
85
+ const endIndex = planJson.lastIndexOf('}');
86
+ parsableJson = planJson.substring(startIndex, endIndex + 1);
87
+ } else {
88
+ throw new Error('Response is not a JSON object');
89
+ }
90
+
91
+ const planData = JSON.parse(parsableJson);
92
+ const { tasks } = planData;
93
+ const { blueprint } = planData;
94
+
95
+ const planId = this.id;
96
+
97
+ for (const task of tasks) {
98
+ await this.db.run(
99
+ 'INSERT INTO tasks (id, title, description, status, dependencies) VALUES (?, ?, ?, ?, ?)',
100
+ task.id,
101
+ task.title,
102
+ task.description,
103
+ 'pending',
104
+ JSON.stringify(task.dependencies),
105
+ );
106
+ }
107
+
108
+ console.log(`Plan saved to database with ${tasks.length} tasks.`);
109
+ return { planId, plan: { tasks, blueprint } };
110
+ } catch (error) {
111
+ console.error('Error parsing JSON plan from API:', error);
112
+ console.error('Received raw API response (expected pure JSON):', planJson);
113
+ throw error;
114
+ }
115
+ }
116
+ throw new Error('Failed to get a plan from the AI model.');
117
+ }
118
+
119
+ async assignTask(task) {
120
+ this.currentTask = task;
121
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'assigned', task.id);
122
+ this.start();
123
+ }
124
+
125
+ async start() {
126
+ console.log(`Operator ${this.name} starting task: ${this.currentTask.title}`);
127
+ await this.executeTask();
128
+ console.log(`Operator ${this.name} finished task: ${this.currentTask.title}`);
129
+ }
130
+
131
+ async executeTask() {
132
+ if (!this.currentTask) {
133
+ throw new Error('No task assigned');
134
+ }
135
+
136
+ try {
137
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'running', this.currentTask.id);
138
+ // AI execution logic will be in the worker
139
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'completed', this.currentTask.id);
140
+ } catch (error) {
141
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'failed', this.currentTask.id);
142
+ throw error;
143
+ }
144
+ }
145
+ }
146
+
147
+ export default Operator;
@@ -0,0 +1,74 @@
1
+ import Agent from './Agent.js';
2
+ import { getDb } from '../utils/db.js';
3
+
4
+ class ScrumAgent extends Agent {
5
+ constructor(name, purpose, aiModel, apiKey, config) {
6
+ super(name, purpose);
7
+ this.aiModel = aiModel;
8
+ this.apiKey = apiKey;
9
+ this.config = config;
10
+ this.db = getDb();
11
+ }
12
+
13
+ static async run() {
14
+ // The ScrumAgent's run loop will be managed by the orchestrator
15
+ }
16
+
17
+ async getNextTask() {
18
+ const pendingTasks = await this.db.all('SELECT * FROM tasks WHERE status = ?', 'pending');
19
+ const completedTasks = (await this.db.all('SELECT id FROM tasks WHERE status = ?', 'completed')).map((t) => t.id);
20
+
21
+ console.log(`DEBUG: Pending: ${pendingTasks.length}, Completed IDs: ${completedTasks.join(',')}`);
22
+ console.log(`DEBUG: Current Config: ${JSON.stringify(this.config)}`);
23
+
24
+ for (const task of pendingTasks) {
25
+ let dependencies = [];
26
+ try {
27
+ dependencies = JSON.parse(task.dependencies);
28
+ } catch (e) {
29
+ console.error(`Error parsing dependencies for task ${task.id}:`, task.dependencies);
30
+ continue;
31
+ }
32
+
33
+ const areDepsMet = this.config.mode === 'yolo' ? true : dependencies.every((dep) => completedTasks.includes(String(dep)));
34
+
35
+ console.log(`DEBUG: Task ${task.id} ("${task.title}") deps: [${dependencies.join(',')}]. Met? ${areDepsMet} (Mode: ${this.config.mode})`);
36
+
37
+ if (areDepsMet) {
38
+ // LOCK IT DOWN: Mark as running immediately to prevent other agents from grabbing it
39
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'running', task.id);
40
+ return task;
41
+ }
42
+ }
43
+
44
+ return null;
45
+ }
46
+
47
+ async assignTaskToAgent(task) {
48
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'assigned', task.id);
49
+ }
50
+
51
+ async markTaskAsCompleted(task) {
52
+ await this.db.run('UPDATE tasks SET status = ? WHERE id = ?', 'completed', task.id);
53
+ }
54
+
55
+ async requeueTask(task) {
56
+ await this.db.run('UPDATE tasks SET status = ?, retries = retries + 1 WHERE id = ?', 'pending', task.id);
57
+ }
58
+
59
+ async addTask(title, description, dependencies = []) {
60
+ const id = Date.now().toString() + Math.floor(Math.random() * 1000).toString();
61
+ await this.db.run(
62
+ 'INSERT INTO tasks (id, title, description, status, dependencies, retries) VALUES (?, ?, ?, ?, ?, ?)',
63
+ id,
64
+ title,
65
+ description,
66
+ 'pending',
67
+ JSON.stringify(dependencies),
68
+ 0,
69
+ );
70
+ return id;
71
+ }
72
+ }
73
+
74
+ export default ScrumAgent;
@@ -0,0 +1,198 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import Agent from './Agent.js';
4
+ import { getDb } from '../utils/db.js';
5
+ import callEmbedApi from '../utils/embedapi.js';
6
+
7
+ class SupervisorAgent extends Agent {
8
+ constructor(name, purpose, aiModel, apiKey, config) {
9
+ super(name, purpose);
10
+ this.aiModel = aiModel;
11
+ this.apiKey = apiKey;
12
+ this.config = config;
13
+ this.db = getDb();
14
+ }
15
+
16
+ async run(projectDescription) {
17
+ console.log('Supervisor initializing...');
18
+
19
+ // 1. Setup Environment
20
+ const imlilDir = path.resolve('.imlil');
21
+ await fs.mkdir(imlilDir, { recursive: true });
22
+
23
+ // 2. Generate Detailed Plan (Markdown)
24
+ console.log('Phase 1: Generating comprehensive plan...');
25
+ const dateStr = new Date().toISOString().split('T')[0];
26
+ const planFilename = `plan-${dateStr}.md`;
27
+ const planPath = path.join(imlilDir, planFilename);
28
+
29
+ const planContent = await this.generatePlan(projectDescription);
30
+ await fs.writeFile(planPath, planContent);
31
+ console.log(` => Plan saved to ${planPath}`);
32
+
33
+ // 3. Generate AST (JSON)
34
+ console.log('Phase 2: Architecting file structure (AST)...');
35
+ const ast = await this.generateAST(projectDescription, planContent);
36
+ await fs.writeFile('ast.json', JSON.stringify(ast, null, 2));
37
+ console.log(' => Project AST saved to ast.json');
38
+
39
+ // 4. Generate Tasks (JSON) linked to AST
40
+ console.log('Phase 3: Deriving actionable tasks...');
41
+ const tasks = await this.generateTasks(planContent, ast);
42
+
43
+ // 5. Populate Database
44
+ console.log('Phase 4: Populating task database...');
45
+ // Clear existing pending tasks if any (optional, but good for clean run)
46
+ // await this.db.run('DELETE FROM tasks');
47
+
48
+ for (const task of tasks) {
49
+ await this.db.run(
50
+ 'INSERT INTO tasks (id, title, description, status, dependencies, retries) VALUES (?, ?, ?, ?, ?, ?)',
51
+ task.id,
52
+ task.title,
53
+ task.description,
54
+ 'pending',
55
+ JSON.stringify(task.dependencies || []),
56
+ 0,
57
+ );
58
+ }
59
+ console.log(` => ${tasks.length} tasks queued in database.`);
60
+
61
+ // 6. Scaffold (optional but good for visual progress)
62
+ console.log('Phase 5: Scaffolding empty files...');
63
+ for (const filePath of Object.keys(ast)) {
64
+ // Skip if value is null or it looks like a directory but is not needed explicitly
65
+ const fullPath = path.resolve(filePath);
66
+ await fs.mkdir(path.dirname(fullPath), { recursive: true });
67
+ try {
68
+ await fs.access(fullPath);
69
+ } catch {
70
+ // Only write if file doesn't exist
71
+ if (!filePath.endsWith('/')) {
72
+ await fs.writeFile(fullPath, '');
73
+ }
74
+ }
75
+ }
76
+
77
+ console.log('Plan ready. Execution handed off to Orchestrator.');
78
+ }
79
+
80
+ async callApiWithRetry(prompt, type = 'json', attempt = 1) {
81
+ const maxRetries = 3;
82
+ if (attempt > maxRetries) {
83
+ throw new Error(`Failed to get valid ${type} response after ${maxRetries} attempts.`);
84
+ }
85
+
86
+ try {
87
+ const response = await callEmbedApi(prompt, this.apiKey);
88
+
89
+ if (type === 'markdown') {
90
+ return response; // No parsing needed
91
+ }
92
+
93
+ // JSON Parsing
94
+ const cleanJson = (res) => {
95
+ const startIndex = res.indexOf('{');
96
+ const endIndex = res.lastIndexOf('}');
97
+ if (startIndex === -1 || endIndex === -1) {
98
+ throw new Error('Could not find JSON object in response');
99
+ }
100
+ return res.substring(startIndex, endIndex + 1);
101
+ };
102
+
103
+ return JSON.parse(cleanJson(response));
104
+ } catch (error) {
105
+ console.error(`Attempt ${attempt} failed: ${error.message}. Retrying...`);
106
+ const newPrompt = `${prompt}\n\n**PREVIOUS ATTEMPT FAILED!**\nYour last response was not valid. Error: "${error.message}". \nPlease correct your output and strictly follow the format requirements.`;
107
+ return this.callApiWithRetry(newPrompt, type, attempt + 1);
108
+ }
109
+ }
110
+
111
+ async generatePlan(description) {
112
+ const prompt = `
113
+ You are a Senior Software Architect.
114
+ Create a comprehensive development plan for the following request: "${description}".
115
+
116
+ **REQUIREMENTS:**
117
+ 1. **Tech Stack:** Explicitly define the technologies, libraries, and tools to be used. (e.g., React, Tailwind, Express, SQLite). Be specific.
118
+ 2. **Conventions:** Define coding standards, naming conventions, and file organization rules.
119
+ 3. **Architecture:** Describe the high-level architecture.
120
+ 4. **Step-by-Step Plan:** A logical sequence of steps to implement the project.
121
+
122
+ **OUTPUT FORMAT:**
123
+ Return the plan as a clean, well-structured MARKDOWN string.
124
+ `;
125
+ return this.callApiWithRetry(prompt, 'markdown');
126
+ }
127
+
128
+ async generateAST(description, planContent) {
129
+ const prompt = `
130
+ You are a System Architect.
131
+ Based on the project plan below, generate a complete JSON Abstract Syntax Tree (AST) representing the file structure of the project.
132
+
133
+ **PLAN:**
134
+ ${planContent}
135
+
136
+ **REQUIREMENTS:**
137
+ - The JSON keys must be the relative file paths (e.g., "src/index.js", "src/components/Header.js").
138
+ - The values should be a brief description of the file's purpose.
139
+ - Include configuration files (package.json, .gitignore, etc.).
140
+ - Ensure the structure supports the defined tech stack.
141
+
142
+ **OUTPUT FORMAT:**
143
+ A single valid JSON object.
144
+ Example:
145
+ {
146
+ "package.json": "Manifest",
147
+ "src/index.js": "Entry point"
148
+ }
149
+ `;
150
+ return this.callApiWithRetry(prompt, 'json');
151
+ }
152
+
153
+ async generateTasks(planContent, ast) {
154
+ const astStr = JSON.stringify(ast, null, 2);
155
+ const prompt = `
156
+ You are a Project Manager.
157
+ Based on the project plan and the file structure (AST), create a list of actionable CRUD tasks to build this project.
158
+
159
+ **PLAN:**
160
+ ${planContent}
161
+
162
+ **FILE STRUCTURE (AST):**
163
+ ${astStr}
164
+
165
+ **REQUIREMENTS:**
166
+ 1. **Granularity:** Each task should focus on creating or modifying specific files.
167
+ 2. **CRUD Type:** Tasks must be clear about their action (Create, Read, Update).
168
+ 3. **Dependencies:** Define task dependencies using IDs.
169
+ 4. **Order:** Ensure tasks are ordered logically (e.g., setup first, then core logic, then UI).
170
+ 5. **Parallelism:** Group independent tasks where possible to allow parallel execution by multiple agents.
171
+
172
+ **OUTPUT FORMAT:**
173
+ A single valid JSON object containing an array of "tasks".
174
+
175
+ Required JSON Structure:
176
+ {
177
+ "tasks": [
178
+ {
179
+ "id": 1,
180
+ "title": "Initialize Project",
181
+ "description": "Create package.json and basic config files.",
182
+ "dependencies": []
183
+ },
184
+ {
185
+ "id": 2,
186
+ "title": "Create Header Component",
187
+ "description": "Implement src/components/Header.js based on the plan.",
188
+ "dependencies": [1]
189
+ }
190
+ ]
191
+ }
192
+ `;
193
+ const result = await this.callApiWithRetry(prompt, 'json');
194
+ return result.tasks;
195
+ }
196
+ }
197
+
198
+ export default SupervisorAgent;
@@ -0,0 +1,48 @@
1
+ import { exec } from 'child_process';
2
+ import util from 'util';
3
+ import Agent from './Agent.js';
4
+
5
+ const execAsync = util.promisify(exec);
6
+
7
+ class ValidatorAgent extends Agent {
8
+ constructor(name, purpose, aiModel, apiKey, config) {
9
+ super(name, purpose);
10
+ this.aiModel = aiModel;
11
+ this.apiKey = apiKey;
12
+ this.config = config;
13
+ }
14
+
15
+ static async validate(task, testPath) {
16
+ try {
17
+ if (!testPath) {
18
+ return { isValid: false, error: 'No test file provided' };
19
+ }
20
+
21
+ if (testPath.endsWith('.js') || testPath.endsWith('.ts') || testPath.endsWith('.jsx') || testPath.endsWith('.tsx')) {
22
+ // For JS/TS/React, we assume npm test or similar.
23
+ // For this MVP, we'll try to run the specific test file using node (if it's a standalone script)
24
+ // or just check if the file exists and has valid syntax if it's a component.
25
+ // A robust solution would run 'npm test <file>'.
26
+
27
+ // Simplified check: Does the file exist?
28
+ const { stdout } = await execAsync(`ls -l ${testPath}`);
29
+ return { isValid: true, output: stdout };
30
+ } if (testPath.endsWith('.c') || testPath.endsWith('.cpp')) {
31
+ // C/C++ validation
32
+ // eslint-disable-next-line max-len
33
+ const { stdout, stderr } = await execAsync(`gcc ${task.filePath || ''} ${testPath} -o test_bin && ./test_bin`);
34
+ if (stderr) {
35
+ return { isValid: false, error: stderr };
36
+ }
37
+ return { isValid: true, output: stdout };
38
+ }
39
+ // Fallback: just check if file exists
40
+ await execAsync(`ls ${testPath}`);
41
+ return { isValid: true, output: 'File created' };
42
+ } catch (error) {
43
+ return { isValid: false, error: error.message };
44
+ }
45
+ }
46
+ }
47
+
48
+ export default ValidatorAgent;