closed-loop-cli 1.0.0

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.

Potentially problematic release.


This version of closed-loop-cli might be problematic. Click here for more details.

Files changed (86) hide show
  1. package/dist/dashboard/server.js +237 -0
  2. package/dist/index.js +272 -0
  3. package/dist/orchestrator/agent-prompts.js +42 -0
  4. package/dist/orchestrator/autogenesis.js +973 -0
  5. package/dist/orchestrator/dgm-archive.js +223 -0
  6. package/dist/orchestrator/event-stream.js +103 -0
  7. package/dist/orchestrator/fitness-evaluator.js +99 -0
  8. package/dist/orchestrator/meta-agent.js +421 -0
  9. package/dist/orchestrator/microagent-registry.js +134 -0
  10. package/dist/orchestrator/mutation-strategies.js +174 -0
  11. package/dist/orchestrator/prompt-benchmark.js +102 -0
  12. package/dist/orchestrator/prompt-optimizer.js +169 -0
  13. package/dist/orchestrator/refactor-scanner.js +222 -0
  14. package/dist/orchestrator/research-manager.js +104 -0
  15. package/dist/orchestrator/rulez.js +135 -0
  16. package/dist/orchestrator/sahoo-gateway.js +261 -0
  17. package/dist/orchestrator/state-manager.js +121 -0
  18. package/dist/orchestrator/task-agent.js +444 -0
  19. package/dist/orchestrator/telegram-bot.js +374 -0
  20. package/dist/orchestrator/types.js +2 -0
  21. package/dist/tests/dynamic/dependencies.test.js +37 -0
  22. package/dist/tests/dynamic/dummy.test.js +7 -0
  23. package/dist/tests/dynamic/fuzzy-patch.test.js +68 -0
  24. package/dist/tests/dynamic/indexer.test.js +60 -0
  25. package/dist/tests/dynamic/openhands.test.js +83 -0
  26. package/dist/tests/dynamic/skills.test.js +88 -0
  27. package/dist/tests/run-tests.js +294 -0
  28. package/dist/tools/diff-tools.js +24 -0
  29. package/dist/tools/file-tools.js +191 -0
  30. package/dist/tools/indexer.js +301 -0
  31. package/dist/tools/math-helper.js +6 -0
  32. package/dist/tools/repo-map.js +122 -0
  33. package/dist/tools/search-tools.js +271 -0
  34. package/dist/tools/shell-tools.js +75 -0
  35. package/dist/tools/skills.js +122 -0
  36. package/dist/tools/tui-tools.js +82 -0
  37. package/docs/AI_Arch_Opt_Anti_Gaming.md +227 -0
  38. package/docs/AI_Self_Improvement_Safety.md +457 -0
  39. package/docs/Anthropic AI Agents_ Capabilities and Concerns.md +134 -0
  40. package/docs/Auto_ClosedLoop_AI_Agent.md +415 -0
  41. package/docs/Autonomous AI Agents_ Closing the Loop.docx +0 -0
  42. package/docs/Secure_AI_Sandbox_Framework.md +358 -0
  43. package/docs/skills/add-file-existence-check-utility.json +9 -0
  44. package/docs/skills/add-utility-function-for-file-existence-check.json +9 -0
  45. package/docs/skills/add-utility-function-to-module.json +9 -0
  46. package/docs/skills/extract-command-runner-utility.json +9 -0
  47. package/docs/skills/file-existence-check-utility.json +9 -0
  48. package/package.json +36 -0
  49. package/src/dashboard/public/index.css +1334 -0
  50. package/src/dashboard/public/index.html +385 -0
  51. package/src/dashboard/public/index.js +1059 -0
  52. package/src/dashboard/server.ts +209 -0
  53. package/src/index.ts +256 -0
  54. package/src/orchestrator/agent-prompts.ts +43 -0
  55. package/src/orchestrator/autogenesis.ts +1078 -0
  56. package/src/orchestrator/dgm-archive.ts +257 -0
  57. package/src/orchestrator/event-stream.ts +90 -0
  58. package/src/orchestrator/fitness-evaluator.ts +154 -0
  59. package/src/orchestrator/meta-agent.ts +434 -0
  60. package/src/orchestrator/microagent-registry.ts +115 -0
  61. package/src/orchestrator/microagents/git-helper.md +11 -0
  62. package/src/orchestrator/microagents/test-fixer.md +10 -0
  63. package/src/orchestrator/microagents/typescript-expert.md +11 -0
  64. package/src/orchestrator/mutation-strategies.ts +214 -0
  65. package/src/orchestrator/research-manager.ts +88 -0
  66. package/src/orchestrator/rulez.ts +118 -0
  67. package/src/orchestrator/sahoo-gateway.ts +300 -0
  68. package/src/orchestrator/state-manager.ts +161 -0
  69. package/src/orchestrator/system-prompt.txt +1 -0
  70. package/src/orchestrator/task-agent.ts +461 -0
  71. package/src/orchestrator/telegram-bot.ts +358 -0
  72. package/src/tests/dynamic/dependencies.test.ts +48 -0
  73. package/src/tests/dynamic/dummy.test.ts +4 -0
  74. package/src/tests/dynamic/fuzzy-patch.test.ts +42 -0
  75. package/src/tests/dynamic/indexer.test.ts +31 -0
  76. package/src/tests/dynamic/openhands.test.ts +59 -0
  77. package/src/tests/dynamic/skills.test.ts +63 -0
  78. package/src/tests/run-tests.ts +296 -0
  79. package/src/tools/diff-tools.ts +27 -0
  80. package/src/tools/file-tools.ts +187 -0
  81. package/src/tools/indexer.ts +325 -0
  82. package/src/tools/repo-map.ts +96 -0
  83. package/src/tools/search-tools.ts +258 -0
  84. package/src/tools/shell-tools.ts +90 -0
  85. package/src/tools/skills.ts +101 -0
  86. package/src/tools/tui-tools.ts +87 -0
@@ -0,0 +1,434 @@
1
+ import Anthropic from '@anthropic-ai/sdk';
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as dotenv from 'dotenv';
5
+ import { runTaskAgent } from './task-agent';
6
+ import { runCommand } from '../tools/shell-tools';
7
+ import { evaluateSahoo } from './sahoo-gateway';
8
+ import { getFormattedDiff } from '../tools/diff-tools';
9
+ import { generateRepoMap } from '../tools/repo-map';
10
+ import { ARCHITECT_PROMPT, CODER_PROMPT, CODEACT_CODER_PROMPT, DEBUGGER_PROMPT, GATEKEEPER_PROMPT } from './agent-prompts';
11
+ import { updateEvolutionState } from './state-manager';
12
+ import { printAgentHeader, printCollapsibleBlock } from '../tools/tui-tools';
13
+ import { ResearchManager } from './research-manager';
14
+ import { MicroagentRegistry } from './microagent-registry';
15
+ import { EventStream } from './event-stream';
16
+
17
+ // Load environment variables
18
+ dotenv.config();
19
+
20
+ const apiKey = process.env.ANTHROPIC_API_KEY || process.env.ANTHROPIC_AUTH_TOKEN || '';
21
+ const baseURL = process.env.ANTHROPIC_BASE_URL || undefined;
22
+ const defaultModel = process.env.ANTHROPIC_MODEL || 'mimo-v2.5-pro[1m]';
23
+
24
+ const anthropic = new Anthropic({
25
+ apiKey: apiKey,
26
+ baseURL: baseURL,
27
+ });
28
+
29
+ /**
30
+ * Runs a task inside the closed-loop system:
31
+ * 1. Reads current codebase rules (CLAUDE.md) and past experiences (Learnings.md).
32
+ * 2. Prepends memory context to the prompt.
33
+ * 3. Executes Task Agent.
34
+ * 4. Extracts learnings from the session logs and writes them back to Learnings.md.
35
+ */
36
+ function getRoleSystemPrompt(
37
+ role: 'architect' | 'coder' | 'debugger' | 'gatekeeper' | 'coder_codeact',
38
+ claudeContext: string,
39
+ learningsContext: string,
40
+ repoMapContext: string,
41
+ osContext: string,
42
+ microagentsContext: string
43
+ ): string {
44
+ let rolePrompt = '';
45
+ switch (role) {
46
+ case 'architect':
47
+ rolePrompt = ARCHITECT_PROMPT;
48
+ break;
49
+ case 'coder':
50
+ rolePrompt = CODER_PROMPT;
51
+ break;
52
+ case 'coder_codeact':
53
+ rolePrompt = CODEACT_CODER_PROMPT;
54
+ break;
55
+ case 'debugger':
56
+ rolePrompt = DEBUGGER_PROMPT;
57
+ break;
58
+ case 'gatekeeper':
59
+ rolePrompt = GATEKEEPER_PROMPT;
60
+ break;
61
+ }
62
+
63
+ // Load custom playbooks from the Skill Registry
64
+ let skillsSummary = 'No custom development skills recorded yet.';
65
+ try {
66
+ const { getSkillsSummary } = require('../tools/skills');
67
+ skillsSummary = getSkillsSummary();
68
+ } catch (e) {}
69
+
70
+ return `You are operating inside a self-improving workspace. You have specialized responsibilities.
71
+ ROLE SPECIFICATION:
72
+ ${rolePrompt}
73
+
74
+ ---
75
+ CRITICAL WORKSPACE GUIDELINES (CLAUDE.md):
76
+ ${claudeContext}
77
+
78
+ ---
79
+ REUSABLE DEVELOPMENT SKILLS (Playbooks derived from past successful evolutions):
80
+ ${skillsSummary}
81
+
82
+ ---
83
+ PAST EXPERIENCE & LEARNINGS (Learnings.md):
84
+ ${learningsContext}
85
+
86
+ ---
87
+ DYNAMICS & INSTRUCTIONS FROM MICROAGENTS:
88
+ ${microagentsContext || 'No microagents active for this context.'}
89
+
90
+ ---
91
+ CODEBASE REPOSITORY MAP (Overview of files and structural signatures):
92
+ ${repoMapContext}
93
+ ---
94
+ ` + osContext;
95
+ }
96
+
97
+ export async function runSelfImprovingTask(task: string, effort: 'standard' | 'ultracode' = 'standard', codeactMode = false): Promise<string> {
98
+ const workspaceRoot = process.cwd();
99
+ const claudePath = path.join(workspaceRoot, 'CLAUDE.md');
100
+ const learningsPath = path.join(workspaceRoot, 'Learnings.md');
101
+
102
+ // 1. Read CLAUDE.md and Learnings.md context
103
+ let claudeContext = '';
104
+ let learningsContext = '';
105
+
106
+ if (fs.existsSync(claudePath)) {
107
+ claudeContext = fs.readFileSync(claudePath, 'utf-8');
108
+ }
109
+ if (fs.existsSync(learningsPath)) {
110
+ learningsContext = fs.readFileSync(learningsPath, 'utf-8');
111
+ }
112
+
113
+ // Generate AST Code Index
114
+ try {
115
+ const { generateCodeIndex } = require('../tools/indexer');
116
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Generating AST code index (code-index.json)...`);
117
+ generateCodeIndex(workspaceRoot);
118
+ } catch (err: any) {
119
+ console.error(`\x1b[31m[MetaAgent] Failed to generate code index: ${err.message}\x1b[0m`);
120
+ }
121
+
122
+ // Generate Repository Map
123
+ let repoMapContext = '';
124
+ try {
125
+ repoMapContext = generateRepoMap(workspaceRoot);
126
+ } catch (err: any) {
127
+ console.error(`\x1b[31m[MetaAgent] Failed to generate codebase map: ${err.message}\x1b[0m`);
128
+ }
129
+
130
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Ingesting memory context and codebase map...`);
131
+
132
+ // Inject OS environment awareness to guide command execution safely
133
+ const osType = process.platform === 'win32' ? 'Windows (win32)' : process.platform;
134
+ const shellType = process.platform === 'win32' ? 'PowerShell or Command Prompt (cmd.exe)' : 'Bash or Sh';
135
+ const osContext = `\n\n---
136
+ CURRENT ENVIRONMENT & OS SAFETY GUIDELINES:
137
+ - Operating System: ${osType}
138
+ - Active Terminal Shell: ${shellType}
139
+ ${process.platform === 'win32' ? `
140
+ IMPORTANT: You are running on Windows. Unix terminal commands such as 'cat', 'ls', 'grep', 'rm -rf', and pipes like '| head' or '| grep' are NOT supported natively.
141
+ - Use Windows/PowerShell equivalent commands (e.g., 'Get-Content' instead of 'cat', 'dir' or 'Get-ChildItem' instead of 'ls', and Node scripts or PowerShell commands for string filtering).
142
+ - Keep commands compatible with Windows environment syntax.` : `
143
+ - Use Unix terminal commands natively compatible with the active shell.`}
144
+ ---`;
145
+
146
+ let targetFile = '';
147
+ let dependencyWarning = '';
148
+ if (task.includes('Refactor the file "')) {
149
+ targetFile = task.split('"')[1];
150
+ } else if (task.includes('file "')) {
151
+ targetFile = task.split('"')[1];
152
+ }
153
+
154
+ if (targetFile) {
155
+ try {
156
+ const { getDependents } = require('../tools/indexer');
157
+ const dependents = getDependents(targetFile, workspaceRoot);
158
+ if (dependents.length > 0) {
159
+ dependencyWarning = `\n\n---
160
+ DEPENDENCY WARNING:
161
+ The file you are modifying ("${targetFile}") is imported by the following files in this project:
162
+ ${dependents.map((f: string) => `- ${f}`).join('\n')}
163
+
164
+ IMPORTANT: Make sure that any changes to function signatures, classes, or exported variables do not break these importing files. If you change exports, you must also update the files importing them.
165
+ ---`;
166
+ console.log(`\x1b[33m[Dependency Guard] Target file "${targetFile}" is imported by: ${JSON.stringify(dependents)}\x1b[0m\n`);
167
+ }
168
+ } catch (e) {
169
+ console.error('[Dependency Guard] Failed to resolve dependents:', e);
170
+ }
171
+ }
172
+
173
+ // Load Microagents context
174
+ const registry = MicroagentRegistry.getInstance();
175
+ registry.loadMicroagents(); // reload to get latest updates
176
+ const matchingAgents = registry.findMatchingMicroagents(task);
177
+ let microagentsContext = '';
178
+ if (matchingAgents.length > 0) {
179
+ microagentsContext = matchingAgents.map(a => `[Microagent: ${a.name}]\nInstructions:\n${a.instructions}`).join('\n\n');
180
+ console.log(`\x1b[32m[MicroagentRegistry]\x1b[0m Triggered Microagents: ${matchingAgents.map(a => a.name).join(', ')}`);
181
+ EventStream.getInstance().publish(
182
+ 'system',
183
+ 'log',
184
+ 'MicroagentsTriggered',
185
+ `Triggered microagents: ${matchingAgents.map(a => a.name).join(', ')}`
186
+ );
187
+ }
188
+
189
+ let result = '';
190
+ let errorMsg = '';
191
+ const startTime = new Date();
192
+
193
+ try {
194
+ // Phase 1: Architect / Planner Agent
195
+ printAgentHeader('architect');
196
+ ResearchManager.logDecision('Architect (Planner)', 'Spawning Planner Agent to generate implementation plan', 'info');
197
+ const architectPrompt = getRoleSystemPrompt('architect', claudeContext, learningsContext, repoMapContext, osContext, microagentsContext);
198
+ const architectReport = await runTaskAgent(task + dependencyWarning, {
199
+ systemPrompt: architectPrompt,
200
+ role: 'architect',
201
+ effort
202
+ });
203
+ const plan = architectReport.result;
204
+ console.log(`\x1b[32m[MetaAgent]\x1b[0m Plan generated successfully:\n${plan}\n`);
205
+ ResearchManager.logDecision('Architect (Planner)', 'Plan generated successfully', 'success', plan);
206
+
207
+ // Phase 2: Coder Agent
208
+ printAgentHeader('coder');
209
+ ResearchManager.logDecision('Coder (Worker)', `Spawning Coder Agent to apply mutations (CodeAct=${codeactMode})`, 'info');
210
+ const coderPrompt = getRoleSystemPrompt(codeactMode ? 'coder_codeact' : 'coder', claudeContext, learningsContext, repoMapContext, osContext, microagentsContext);
211
+ const coderReport = await runTaskAgent(`Here is the task you must implement:\n"${task}"\n\nHere is the approved design plan/blueprint to guide your implementation:\n"""\n${plan}\n"""\n\nPlease implement the code changes as planned. Use editFile or writeFile to execute the plan.`, {
212
+ systemPrompt: coderPrompt,
213
+ role: codeactMode ? 'coder_codeact' as any : 'coder',
214
+ effort
215
+ });
216
+ result = coderReport.result;
217
+ console.log(`\x1b[32m[MetaAgent]\x1b[0m Code mutations applied.`);
218
+ ResearchManager.logDecision('Coder (Worker)', 'Coder mutated files successfully based on design plan', 'success', result);
219
+
220
+ // Phase 3: Inner Self-Healing Loop (Debugger <-> Coder)
221
+ const healCycles = 3;
222
+ let buildSuccess = false;
223
+ let testSuccess = false;
224
+
225
+ for (let cycle = 1; cycle <= healCycles; cycle++) {
226
+ console.log(`\n\x1b[34m[MetaAgent]\x1b[0m Verification Loop - Cycle ${cycle}/${healCycles}: Running compilation check...`);
227
+ ResearchManager.logDecision('Verification', `Running compilation check (Cycle ${cycle}/${healCycles})`, 'info');
228
+ const compileRes = await runCommand('npm run build');
229
+ buildSuccess = compileRes.exitCode === 0;
230
+
231
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Verification Loop - Cycle ${cycle}/${healCycles}: Running tests check...`);
232
+ ResearchManager.logDecision('Verification', `Running unit tests (Cycle ${cycle}/${healCycles})`, 'info');
233
+ const testRes = await runCommand('npm test');
234
+ testSuccess = testRes.exitCode === 0;
235
+
236
+ if (buildSuccess && testSuccess) {
237
+ console.log(`\x1b[32m[MetaAgent]\x1b[0m Codebase compile & test execution passed! Code is healthy.\x1b[0m`);
238
+ ResearchManager.logDecision('Verification', 'Compilation & unit tests passed successfully', 'success');
239
+ break;
240
+ }
241
+
242
+ const errorLog = `Compilation Output:\nExit Code: ${compileRes.exitCode}\nStdout:\n${compileRes.stdout}\nStderr:\n${compileRes.stderr}\n\nTest Suite Output:\nExit Code: ${testRes.exitCode}\nStdout:\n${testRes.stdout}\nStderr:\n${testRes.stderr}`;
243
+ ResearchManager.logDecision('Verification', `Build/tests failed (Cycle ${cycle}/${healCycles})`, 'failure', errorLog);
244
+
245
+ if (cycle < healCycles) {
246
+ printAgentHeader('debugger');
247
+ console.log(`\x1b[33m[MetaAgent] Build/tests failed. Invoking Diagnostics & Debugger Agent to analyze errors...\x1b[0m`);
248
+ ResearchManager.logDecision('Debugger', 'Spawning Debugger Agent to analyze compilation/test errors', 'info');
249
+ const debuggerPrompt = getRoleSystemPrompt('debugger', claudeContext, learningsContext, repoMapContext, osContext, microagentsContext);
250
+ const debuggerReport = await runTaskAgent(`The code modification failed verification. Here is the compile/test execution log:\n\n${errorLog}\n\nPlease inspect the error trace, identify the exact lines and files of code that caused the issue, and output a specific, actionable instruction for the Coder agent to fix it. Do NOT make file changes yourself.`, {
251
+ systemPrompt: debuggerPrompt,
252
+ role: 'debugger',
253
+ effort
254
+ });
255
+
256
+ console.log(`\x1b[33m[MetaAgent] Diagnostic feedback received. Re-running Coder Agent to apply the fix...\x1b[0m`);
257
+ ResearchManager.logDecision('Debugger', 'Diagnostic advice generated', 'success', debuggerReport.result);
258
+
259
+ ResearchManager.logDecision('Coder (Worker)', `Applying corrections based on diagnostic instructions (Cycle ${cycle}/${healCycles})`, 'info');
260
+ const correctionTask = `The previous implementation caused build/test failures.
261
+ Here is the error trace:
262
+ ${errorLog}
263
+
264
+ Here is the diagnostic instruction from the Debugger agent:
265
+ "${debuggerReport.result}"
266
+
267
+ Please make the necessary file edits (using editFile or writeFile) to correct the codebase.`;
268
+
269
+ const recoderReport = await runTaskAgent(correctionTask, {
270
+ systemPrompt: coderPrompt,
271
+ role: 'coder',
272
+ effort
273
+ });
274
+ result = recoderReport.result;
275
+ ResearchManager.logDecision('Coder (Worker)', `Applied corrections (Cycle ${cycle}/${healCycles})`, 'success');
276
+ } else {
277
+ console.log(`\x1b[31m[MetaAgent] Build/tests failed after maximum self-healing cycles.\x1b[0m`);
278
+ ResearchManager.logDecision('Verification', `Self-healing failed to stabilize build and tests after ${healCycles} attempts`, 'failure');
279
+ throw new Error(`Self-healing failed to stabilize build and tests after ${healCycles} attempts.\n${errorLog}`);
280
+ }
281
+ }
282
+
283
+ // Phase 4: Gatekeeper & Reviewer Agent
284
+ printAgentHeader('gatekeeper');
285
+ ResearchManager.logDecision('Gatekeeper', 'Spawning Gatekeeper Agent to perform safety and quality review', 'info');
286
+ const gatekeeperPrompt = getRoleSystemPrompt('gatekeeper', claudeContext, learningsContext, repoMapContext, osContext, microagentsContext);
287
+
288
+ // Find modified files via git status
289
+ const gitStatus = await runCommand('git status --porcelain');
290
+ const modifiedFiles: string[] = [];
291
+
292
+ if (gitStatus.exitCode === 0 && gitStatus.stdout.trim()) {
293
+ const lines = gitStatus.stdout.split('\n');
294
+ for (const line of lines) {
295
+ const trimmed = line.trim();
296
+ if (trimmed.startsWith('M ') || trimmed.startsWith('A ') || trimmed.startsWith('?? ')) {
297
+ const filePath = trimmed.substring(2).trim();
298
+ if (filePath && !filePath.includes('Learnings.md') && !filePath.includes('.env') && !filePath.includes('code-index.json')) {
299
+ modifiedFiles.push(filePath);
300
+ }
301
+ }
302
+ }
303
+ }
304
+
305
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Modified files detected: ${JSON.stringify(modifiedFiles)}`);
306
+
307
+ if (modifiedFiles.length > 0) {
308
+ const diffRes = await runCommand('git diff');
309
+ const reviewerReport = await runTaskAgent(`Please review the modifications in the git diff below and confirm if they compile and are safe:\n\n${diffRes.stdout}\n\nIf anything is unsafe or incorrect, raise a concern.`, {
310
+ systemPrompt: gatekeeperPrompt,
311
+ role: 'gatekeeper',
312
+ effort
313
+ });
314
+ console.log(`\x1b[32m[MetaAgent]\x1b[0m Reviewer comments:\n${reviewerReport.result}\n`);
315
+ ResearchManager.logDecision('Gatekeeper', 'Safety & quality audit report complete', 'success', reviewerReport.result);
316
+
317
+ for (const filePath of modifiedFiles) {
318
+ const fullPath = path.join(workspaceRoot, filePath);
319
+
320
+ let afterContent = '';
321
+ if (fs.existsSync(fullPath)) {
322
+ afterContent = fs.readFileSync(fullPath, 'utf-8');
323
+ }
324
+
325
+ // Get beforeContent using git show HEAD:path
326
+ let beforeContent = '';
327
+ try {
328
+ const beforeRes = await runCommand(`git show HEAD:${filePath.replace(/\\/g, '/')}`);
329
+ if (beforeRes.exitCode === 0) {
330
+ beforeContent = beforeRes.stdout;
331
+ }
332
+ } catch (e) {
333
+ // If file is new, beforeContent remains empty
334
+ }
335
+
336
+ ResearchManager.logDecision('SAHOO Safety Gate', `Evaluating SAHOO policies for ${filePath}`, 'info');
337
+ const sahooRes = evaluateSahoo(filePath, beforeContent, afterContent, buildSuccess, testSuccess);
338
+
339
+ if (!sahooRes.passed) {
340
+ console.log(`\x1b[31m[SAHOO HALT TRIGGERED]\x1b[0m ${sahooRes.reason}`);
341
+ console.log(`\x1b[31m[MetaAgent] SAHOO Gateway Rejected changes. Rolling back codebase...\x1b[0m`);
342
+ ResearchManager.logDecision('SAHOO Safety Gate', `SAHOO rejected change in ${filePath}: ${sahooRes.reason}`, 'failure');
343
+
344
+ updateEvolutionState({
345
+ lastRefactorResult: {
346
+ success: false,
347
+ targetFile: filePath,
348
+ message: `SAHOO Gateway Rejected: ${sahooRes.reason}`,
349
+ time: new Date().toISOString(),
350
+ metrics: sahooRes.metrics,
351
+ reason: sahooRes.reason
352
+ }
353
+ });
354
+
355
+ // Execute git rollback (revert all changes)
356
+ ResearchManager.logDecision('Rollback', 'Reverting workspace modifications via git reset to preserve stability', 'info');
357
+ await runCommand('git reset --hard HEAD');
358
+ await runCommand('git clean -fd');
359
+
360
+ throw new Error(`SAHOO Policy Violation: ${sahooRes.reason}. Reverted all changes to preserve system stability.`);
361
+ } else {
362
+ console.log(`\x1b[32m[SAHOO Passed]\x1b[0m File: ${filePath} | GDI: ${sahooRes.metrics.goalDriftIndex.toFixed(3)} | CPS: ${sahooRes.metrics.constraintPreservationScore}`);
363
+ console.log(await getFormattedDiff(filePath));
364
+ ResearchManager.logDecision('SAHOO Safety Gate', `SAHOO passed for ${filePath}`, 'success');
365
+
366
+ updateEvolutionState({
367
+ lastRefactorResult: {
368
+ success: true,
369
+ targetFile: filePath,
370
+ message: 'SAHOO Gateway passed.',
371
+ time: new Date().toISOString(),
372
+ metrics: sahooRes.metrics
373
+ }
374
+ });
375
+ }
376
+ }
377
+ }
378
+ } catch (err: any) {
379
+ errorMsg = err.message;
380
+ console.error(`\x1b[31m[MetaAgent] Multi-Agent run encountered an error: ${errorMsg}\x1b[0m`);
381
+ }
382
+
383
+ const endTime = new Date();
384
+ const elapsedMinutes = ((endTime.getTime() - startTime.getTime()) / 60000).toFixed(1);
385
+
386
+ // 4. Summarize and write learnings to Learnings.md (Closing the Loop)
387
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Synthesizing learnings from session...`);
388
+
389
+ const dateStr = startTime.toISOString().split('T')[0];
390
+ const summaryPrompt = `Based on the following session logs, extract the key learnings in the strict Learnings.md format.
391
+ Include:
392
+ 1. Observation (สิ่งที่พบ): What succeeded, failed, linter errors, or quirks of the codebase.
393
+ 2. Action (การแก้ไข): The precise changes, command fixes, or prompt templates adjusted.
394
+ 3. Confidence: A decimal from 0.0 to 1.0.
395
+
396
+ Session Details:
397
+ - Task: "${task}"
398
+ - Duration: ${elapsedMinutes} minutes
399
+ - Status: ${errorMsg ? 'FAILED with error: ' + errorMsg : 'SUCCESS'}
400
+ - Agent Output: "${result}"
401
+
402
+ Return ONLY the markdown section matching:
403
+ ### YYYY-MM-DD - [Task Name]
404
+ - **Observation (สิ่งที่พบ)**: ...
405
+ - **Action (การแก้ไข)**: ...
406
+ - **Confidence (ความมั่นใจ 0-1)**: ...
407
+ `;
408
+
409
+ try {
410
+ const summaryResponse = await anthropic.messages.create({
411
+ model: defaultModel,
412
+ max_tokens: 1000,
413
+ messages: [{ role: 'user', content: summaryPrompt }],
414
+ });
415
+
416
+ const summaryBlock = summaryResponse.content.find(b => b.type === 'text') as Anthropic.TextBlock | undefined;
417
+ if (summaryBlock && summaryBlock.text) {
418
+ const learningsText = summaryBlock.text.trim();
419
+
420
+ console.log(`\n\x1b[32m[New Learnings Formulated]:\x1b[0m\n${learningsText}\n`);
421
+
422
+ // Append to Learnings.md
423
+ fs.appendFileSync(learningsPath, `\n${learningsText}\n`, 'utf-8');
424
+ console.log(`\x1b[34m[MetaAgent]\x1b[0m Successfully updated Learnings.md`);
425
+ }
426
+ } catch (summaryErr: any) {
427
+ console.error(`\x1b[31m[MetaAgent] Failed to write learnings to Learnings.md: ${summaryErr.message}\x1b[0m`);
428
+ }
429
+
430
+ if (errorMsg) {
431
+ throw new Error(errorMsg);
432
+ }
433
+ return result;
434
+ }
@@ -0,0 +1,115 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ export interface Microagent {
5
+ name: string;
6
+ trigger: string;
7
+ description: string;
8
+ instructions: string;
9
+ }
10
+
11
+ export class MicroagentRegistry {
12
+ private static instance: MicroagentRegistry;
13
+ private microagents: Microagent[] = [];
14
+ private dirPath: string;
15
+
16
+ private constructor() {
17
+ this.dirPath = path.join(process.cwd(), 'src', 'orchestrator', 'microagents');
18
+ this.ensureDirectoryExists();
19
+ this.loadMicroagents();
20
+ }
21
+
22
+ public static getInstance(): MicroagentRegistry {
23
+ if (!MicroagentRegistry.instance) {
24
+ MicroagentRegistry.instance = new MicroagentRegistry();
25
+ }
26
+ return MicroagentRegistry.instance;
27
+ }
28
+
29
+ private ensureDirectoryExists() {
30
+ if (!fs.existsSync(this.dirPath)) {
31
+ fs.mkdirSync(this.dirPath, { recursive: true });
32
+ }
33
+ }
34
+
35
+ public loadMicroagents() {
36
+ this.microagents = [];
37
+ if (!fs.existsSync(this.dirPath)) return;
38
+
39
+ try {
40
+ const files = fs.readdirSync(this.dirPath);
41
+ for (const file of files) {
42
+ if (file.endsWith('.md')) {
43
+ const filePath = path.join(this.dirPath, file);
44
+ const content = fs.readFileSync(filePath, 'utf-8');
45
+ const microagent = this.parseMicroagent(content);
46
+ if (microagent) {
47
+ this.microagents.push(microagent);
48
+ }
49
+ }
50
+ }
51
+ console.log(`[MicroagentRegistry] Loaded ${this.microagents.length} microagents.`);
52
+ } catch (e) {
53
+ console.error('[MicroagentRegistry] Failed to load microagents:', e);
54
+ }
55
+ }
56
+
57
+ private parseMicroagent(content: string): Microagent | null {
58
+ // Simple YAML frontmatter parser
59
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
60
+ if (!match) return null;
61
+
62
+ const frontmatter = match[1];
63
+ const instructions = match[2].trim();
64
+
65
+ const metadata: any = {};
66
+ const lines = frontmatter.split('\n');
67
+ for (const line of lines) {
68
+ const parts = line.split(':');
69
+ if (parts.length >= 2) {
70
+ const key = parts[0].trim();
71
+ const value = parts.slice(1).join(':').trim();
72
+ metadata[key] = value;
73
+ }
74
+ }
75
+
76
+ if (!metadata.name || !metadata.trigger) {
77
+ return null;
78
+ }
79
+
80
+ return {
81
+ name: metadata.name,
82
+ trigger: metadata.trigger,
83
+ description: metadata.description || '',
84
+ instructions
85
+ };
86
+ }
87
+
88
+ public getMicroagents(): Microagent[] {
89
+ return this.microagents;
90
+ }
91
+
92
+ /**
93
+ * Returns microagents whose triggers match the query/context string.
94
+ */
95
+ public findMatchingMicroagents(query: string): Microagent[] {
96
+ const matched: Microagent[] = [];
97
+ const lowerQuery = query.toLowerCase();
98
+
99
+ for (const agent of this.microagents) {
100
+ try {
101
+ const regex = new RegExp(agent.trigger, 'i');
102
+ if (regex.test(lowerQuery)) {
103
+ matched.push(agent);
104
+ }
105
+ } catch (e) {
106
+ // Fallback to substring match if regex is invalid
107
+ if (lowerQuery.includes(agent.trigger.toLowerCase())) {
108
+ matched.push(agent);
109
+ }
110
+ }
111
+ }
112
+
113
+ return matched;
114
+ }
115
+ }
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: Git Helper
3
+ trigger: (git|commit|push|checkout|branch|stash)
4
+ description: Provides guidelines for safe and clean Git operations in Closed-Loop
5
+ ---
6
+ When executing Git operations:
7
+ 1. Do not use `--force` on any shared branches.
8
+ 2. Ensure you never commit uncompiled or failing code to main branches.
9
+ 3. Use clear, descriptive commit messages containing the task details.
10
+ 4. If rolling back, use git reset --hard HEAD followed by git clean -fd.
11
+ 5. Never attempt to push to remote unless explicitly authorized.
@@ -0,0 +1,10 @@
1
+ ---
2
+ name: Test Fixer
3
+ trigger: (test|fail|error|assert|expect|broken|diagnose)
4
+ description: Provides strategies for diagnosing and repairing broken unit tests
5
+ ---
6
+ When repairing failing tests:
7
+ 1. Examine the test report details, specifically looking for expected vs actual outcomes.
8
+ 2. Check if a dependency change caused regression in other modules.
9
+ 3. Keep test logic separate from business logic; don't change tests to fit broken logic unless the test itself is incorrect.
10
+ 4. Run npm run build first before running npm test to ensure you are testing the latest version.
@@ -0,0 +1,11 @@
1
+ ---
2
+ name: TypeScript Expert
3
+ trigger: (\.ts|typescript|tsc|compile|strict|interface|type)
4
+ description: Promotes standard TypeScript guidelines and practices
5
+ ---
6
+ TypeScript development guidelines:
7
+ 1. Prefer explicit typing over 'any' wherever possible to maintain type safety.
8
+ 2. Use interfaces or type aliases for defining structured models.
9
+ 3. Make sure to run `npm run build` frequently to catch compilation issues early.
10
+ 4. Export only modules, functions, and interfaces that are intended to be public API.
11
+ 5. Use correct CommonJS import/export semantics since the target project uses CommonJS.