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,214 @@
1
+ import { DGMArchive, ArchiveEntry } from './dgm-archive';
2
+
3
+ /**
4
+ * DGM Mutation Strategies
5
+ *
6
+ * จาก DGM paper: open-ended evolution ต้องการ diversity ของ mutation types
7
+ * ไม่ใช่แค่ refactor อย่างเดียว — เพื่อสำรวจ search space ที่กว้างขึ้น
8
+ */
9
+ export enum MutationStrategy {
10
+ /** เพิ่ม feature ใหม่เข้าไปในระบบ */
11
+ ADD_FEATURE = 'add_feature',
12
+ /** Refactor code เดิมให้อ่านง่ายขึ้น / ลด duplication */
13
+ REFACTOR = 'refactor',
14
+ /** Optimize performance หรือ token efficiency */
15
+ OPTIMIZE = 'optimize',
16
+ /** เพิ่ม unit tests เพื่อเพิ่ม coverage */
17
+ ADD_TESTS = 'add_tests',
18
+ /** แก้ bug ที่ตรวจพบจาก test failures */
19
+ FIX_BUG = 'fix_bug',
20
+ /** ปรับปรุง system prompt / agent prompt */
21
+ IMPROVE_PROMPT = 'improve_prompt',
22
+ }
23
+
24
+ /**
25
+ * ผลการเลือก mutation strategy
26
+ */
27
+ export interface MutationSelection {
28
+ strategy: MutationStrategy;
29
+ rationale: string;
30
+ targetHint?: string;
31
+ }
32
+
33
+ /**
34
+ * เลือก mutation strategy ที่เหมาะสมจาก archive history + task context
35
+ *
36
+ * DGM approach: strategy selection ควร adaptive ตาม population history
37
+ * — ถ้า fitness ต่ำ → ลอง ADD_TESTS หรือ FIX_BUG ก่อน
38
+ * — ถ้า fitness สูงแล้ว → ลอง ADD_FEATURE หรือ OPTIMIZE
39
+ * — ถ้า task พูดถึง bug → เลือก FIX_BUG ก่อน
40
+ */
41
+ export function selectMutationStrategy(
42
+ archive: DGMArchive,
43
+ task: string,
44
+ currentFitness: number = 0
45
+ ): MutationSelection {
46
+ const taskLower = task.toLowerCase();
47
+
48
+ // 1. Task-based override: ถ้า task บ่งชี้ strategy ชัดเจน
49
+ if (taskLower.includes('fix') || taskLower.includes('bug') || taskLower.includes('error')) {
50
+ return {
51
+ strategy: MutationStrategy.FIX_BUG,
52
+ rationale: 'Task description indicates a bug fix is needed'
53
+ };
54
+ }
55
+
56
+ if (taskLower.includes('test') || taskLower.includes('coverage')) {
57
+ return {
58
+ strategy: MutationStrategy.ADD_TESTS,
59
+ rationale: 'Task description requests test improvements'
60
+ };
61
+ }
62
+
63
+ if (taskLower.includes('prompt') || taskLower.includes('instruction')) {
64
+ return {
65
+ strategy: MutationStrategy.IMPROVE_PROMPT,
66
+ rationale: 'Task description targets prompt engineering'
67
+ };
68
+ }
69
+
70
+ if (taskLower.includes('refactor') || taskLower.includes('clean') || taskLower.includes('reformat')) {
71
+ return {
72
+ strategy: MutationStrategy.REFACTOR,
73
+ rationale: 'Task description requests code refactoring'
74
+ };
75
+ }
76
+
77
+ if (taskLower.includes('optim') || taskLower.includes('speed') || taskLower.includes('performance') || taskLower.includes('token')) {
78
+ return {
79
+ strategy: MutationStrategy.OPTIMIZE,
80
+ rationale: 'Task description requests optimization'
81
+ };
82
+ }
83
+
84
+ if (taskLower.includes('add') || taskLower.includes('implement') || taskLower.includes('create') || taskLower.includes('new feature')) {
85
+ return {
86
+ strategy: MutationStrategy.ADD_FEATURE,
87
+ rationale: 'Task description requests adding a new feature'
88
+ };
89
+ }
90
+
91
+ // 2. Fitness-based heuristic: ถ้า fitness ต่ำ → focus on fixing
92
+ if (currentFitness < 0.7) {
93
+ return {
94
+ strategy: MutationStrategy.FIX_BUG,
95
+ rationale: `Low fitness (${(currentFitness * 100).toFixed(1)}%) — prioritizing stability fixes`
96
+ };
97
+ }
98
+
99
+ // 3. Archive diversity: ตรวจสอบว่า strategy ไหนถูกใช้ไปน้อยสุดใน archive
100
+ const recentHistory = archive.getRecentHistory(8);
101
+ if (recentHistory.length > 0) {
102
+ const strategyCounts: Record<string, number> = {};
103
+ for (const s of Object.values(MutationStrategy)) {
104
+ strategyCounts[s] = 0;
105
+ }
106
+ for (const entry of recentHistory) {
107
+ if (entry.mutationStrategy && strategyCounts[entry.mutationStrategy] !== undefined) {
108
+ strategyCounts[entry.mutationStrategy]++;
109
+ }
110
+ }
111
+
112
+ // เลือก strategy ที่ถูกใช้น้อยสุด (diversity promotion)
113
+ const leastUsed = Object.entries(strategyCounts)
114
+ .sort((a, b) => a[1] - b[1])[0];
115
+
116
+ if (leastUsed && leastUsed[1] < 2) {
117
+ return {
118
+ strategy: leastUsed[0] as MutationStrategy,
119
+ rationale: `Diversity promotion: "${leastUsed[0]}" has been used least (${leastUsed[1]}x in recent history)`
120
+ };
121
+ }
122
+ }
123
+
124
+ // 4. Default: ADD_FEATURE (DGM paper prefers expansive mutations)
125
+ return {
126
+ strategy: MutationStrategy.ADD_FEATURE,
127
+ rationale: 'Default open-ended evolution strategy: expanding capabilities'
128
+ };
129
+ }
130
+
131
+ /**
132
+ * สร้าง task prompt เฉพาะ mutation strategy
133
+ * ให้ Agent ทราบว่ากำลังทำ mutation ประเภทใด
134
+ */
135
+ export function generateMutationPrompt(
136
+ strategy: MutationStrategy,
137
+ originalTask: string,
138
+ context?: {
139
+ targetFile?: string;
140
+ parentEntry?: ArchiveEntry | null;
141
+ currentFitness?: number;
142
+ }
143
+ ): string {
144
+ const parentInfo = context?.parentEntry
145
+ ? `\n[DGM Context] Building upon parent snapshot: ${context.parentEntry.id} (fitness: ${(context.parentEntry.fitness * 100).toFixed(1)}%)`
146
+ : '';
147
+
148
+ const fitnessInfo = context?.currentFitness !== undefined
149
+ ? `\n[DGM Context] Current system fitness: ${(context.currentFitness * 100).toFixed(1)}% (test pass rate)`
150
+ : '';
151
+
152
+ const fileInfo = context?.targetFile
153
+ ? `\n[DGM Context] Primary target file: ${context.targetFile}`
154
+ : '';
155
+
156
+ const dgmHeader = `[DGM Mutation: ${strategy.toUpperCase()}]${parentInfo}${fitnessInfo}${fileInfo}\n\n`;
157
+
158
+ switch (strategy) {
159
+ case MutationStrategy.ADD_FEATURE:
160
+ return dgmHeader +
161
+ `Your mutation goal is to ADD A NEW FEATURE. Implement the following capability:\n${originalTask}\n\n` +
162
+ `Guidelines:\n` +
163
+ `- Create new files or add new exported functions/classes as needed\n` +
164
+ `- Do not break existing functionality\n` +
165
+ `- Ensure all new code compiles and existing tests still pass\n` +
166
+ `- The feature should integrate cleanly with the existing codebase`;
167
+
168
+ case MutationStrategy.REFACTOR:
169
+ return dgmHeader +
170
+ `Your mutation goal is to REFACTOR existing code for better quality:\n${originalTask}\n\n` +
171
+ `Guidelines:\n` +
172
+ `- Improve readability, reduce duplication, or strengthen type safety\n` +
173
+ `- Preserve all existing behavior exactly (zero functional change)\n` +
174
+ `- All existing tests must still pass after refactoring`;
175
+
176
+ case MutationStrategy.OPTIMIZE:
177
+ return dgmHeader +
178
+ `Your mutation goal is to OPTIMIZE for performance or efficiency:\n${originalTask}\n\n` +
179
+ `Guidelines:\n` +
180
+ `- Focus on reducing token usage, execution time, or memory\n` +
181
+ `- Preserve correctness — all tests must still pass\n` +
182
+ `- Measure and report the optimization impact if possible`;
183
+
184
+ case MutationStrategy.ADD_TESTS:
185
+ return dgmHeader +
186
+ `Your mutation goal is to ADD UNIT TESTS to improve coverage:\n${originalTask}\n\n` +
187
+ `Guidelines:\n` +
188
+ `- Add tests to src/tests/dynamic/ directory as .ts files\n` +
189
+ `- Tests must export a default function or a run() function\n` +
190
+ `- Prioritize testing edge cases and untested public functions\n` +
191
+ `- Do not modify existing test files (protected by Campbell Regime)`;
192
+
193
+ case MutationStrategy.FIX_BUG:
194
+ return dgmHeader +
195
+ `Your mutation goal is to FIX A BUG or stability issue:\n${originalTask}\n\n` +
196
+ `Guidelines:\n` +
197
+ `- Diagnose the root cause carefully before making changes\n` +
198
+ `- Make the minimal change required to fix the issue\n` +
199
+ `- Add a regression test if appropriate\n` +
200
+ `- All tests must pass after the fix`;
201
+
202
+ case MutationStrategy.IMPROVE_PROMPT:
203
+ return dgmHeader +
204
+ `Your mutation goal is to IMPROVE AGENT PROMPTS for better performance:\n${originalTask}\n\n` +
205
+ `Guidelines:\n` +
206
+ `- Edit src/orchestrator/system-prompt.txt or src/orchestrator/agent-prompts.ts\n` +
207
+ `- Make prompts more concise, clear, and effective\n` +
208
+ `- Preserve all existing agent capabilities\n` +
209
+ `- Build compiles and tests pass after changes`;
210
+
211
+ default:
212
+ return dgmHeader + originalTask;
213
+ }
214
+ }
@@ -0,0 +1,88 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+
4
+ export interface ResearchDecision {
5
+ timestamp: string;
6
+ phase: string;
7
+ action: string;
8
+ result: 'success' | 'failure' | 'info';
9
+ details?: string;
10
+ }
11
+
12
+ export interface ResearchSession {
13
+ taskId: string;
14
+ task: string;
15
+ startedAt: string;
16
+ endedAt?: string;
17
+ status: 'running' | 'success' | 'failed';
18
+ effort: 'standard' | 'ultracode';
19
+ decisions: ResearchDecision[];
20
+ }
21
+
22
+ export class ResearchManager {
23
+ private static session: ResearchSession | null = null;
24
+ private static logPath = path.join(process.cwd(), 'research-log.json');
25
+
26
+ static startSession(task: string, effort: 'standard' | 'ultracode') {
27
+ this.session = {
28
+ taskId: `task-${Date.now()}`,
29
+ task,
30
+ startedAt: new Date().toISOString(),
31
+ status: 'running',
32
+ effort,
33
+ decisions: []
34
+ };
35
+ this.logDecision('session_start', `Starting active research session for task: "${task}"`, 'info');
36
+ this.saveSession();
37
+ }
38
+
39
+ static logDecision(phase: string, action: string, result: 'success' | 'failure' | 'info', details?: string) {
40
+ if (!this.session) return;
41
+
42
+ this.session.decisions.push({
43
+ timestamp: new Date().toISOString(),
44
+ phase,
45
+ action,
46
+ result,
47
+ details
48
+ });
49
+ this.saveSession();
50
+ }
51
+
52
+ static endSession(status: 'success' | 'failed') {
53
+ if (!this.session) return;
54
+ this.session.status = status;
55
+ this.session.endedAt = new Date().toISOString();
56
+ this.logDecision('session_end', `Session ended with status: ${status}`, 'info');
57
+ this.saveSession();
58
+ this.session = null;
59
+ }
60
+
61
+ private static saveSession() {
62
+ if (!this.session) return;
63
+ try {
64
+ let sessions: ResearchSession[] = [];
65
+ if (fs.existsSync(this.logPath)) {
66
+ try {
67
+ sessions = JSON.parse(fs.readFileSync(this.logPath, 'utf-8'));
68
+ } catch (e) {}
69
+ }
70
+
71
+ const index = sessions.findIndex(s => s.taskId === this.session!.taskId);
72
+ if (index !== -1) {
73
+ sessions[index] = this.session;
74
+ } else {
75
+ sessions.push(this.session);
76
+ }
77
+
78
+ // Keep last 10 sessions to save space
79
+ if (sessions.length > 10) {
80
+ sessions.shift();
81
+ }
82
+
83
+ fs.writeFileSync(this.logPath, JSON.stringify(sessions, null, 2), 'utf-8');
84
+ } catch (err) {
85
+ console.error('[ResearchManager] Failed to write research log:', err);
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,118 @@
1
+ import * as path from 'path';
2
+
3
+ export interface PolicyResult {
4
+ allowed: boolean;
5
+ exitCode: number;
6
+ message: string;
7
+ }
8
+
9
+ // Banned command substrings
10
+ const BANNED_COMMAND_PATTERNS = [
11
+ /\brm\b\s+-[rf]{1,2}\s+\//, // rm -rf /
12
+ /\brm\b\s+-[rf]{1,2}\s+\./, // rm -rf .
13
+ /\brm\b\s+-[rf]{1,2}\s+([A-Za-z]:)?\\/, // Windows root deletes
14
+ /\bformat\b/i, // disk formats
15
+ /\bgit\b.*\bpush\b.*\b--force\b/, // force pushes
16
+ /\bgit\b.*\bpush\b/, // any direct push to remote
17
+ /\bchmod\b\s+777/, // unsafe permissions elevation
18
+ /\bchown\b/, // ownership tampering
19
+ /(\bdrop\b|\balter\b)\s+database/i // raw database drops
20
+ ];
21
+
22
+ // Secrets patterns (e.g. tp- tokens, standard slack tokens, etc)
23
+ const SECRETS_PATTERNS = [
24
+ /tp-[a-zA-Z0-9]{32,}/, // MiMo tp- Token pattern
25
+ /sk-[a-zA-Z0-9]{20,}/, // standard OpenAI/Anthropic keys
26
+ /API_KEY\s*=\s*['"][a-zA-Z0-9_-]{16,}['"]/i,
27
+ /PASSWORD\s*=\s*['"][a-zA-Z0-9_-]{8,}['"]/i
28
+ ];
29
+
30
+ /**
31
+ * Checks if a command string is allowed under RuleZ policies.
32
+ */
33
+ export function checkCommand(commandStr: string): PolicyResult {
34
+ const normalizedCmd = commandStr.trim();
35
+
36
+ // 1. Check for banned command patterns
37
+ for (const pattern of BANNED_COMMAND_PATTERNS) {
38
+ if (pattern.test(normalizedCmd)) {
39
+ return {
40
+ allowed: false,
41
+ exitCode: 2,
42
+ message: `Blocked by RuleZ: Command violates security policy (matches pattern: ${pattern.toString()})`
43
+ };
44
+ }
45
+ }
46
+
47
+ // 2. Safe commands allowed
48
+ return {
49
+ allowed: true,
50
+ exitCode: 0,
51
+ message: 'Allowed by RuleZ'
52
+ };
53
+ }
54
+
55
+ /**
56
+ * Checks if a file edit or write is allowed under RuleZ policies.
57
+ */
58
+ export function checkFileEdit(filePath: string, content: string): PolicyResult {
59
+ // 1. Protected files lockout (Campbell Safeguard Policy)
60
+ const normalizedPath = filePath.replace(/\\/g, '/');
61
+ const normalizedFile = normalizedPath.toLowerCase();
62
+ const resolvedBaseName = path.basename(filePath).toLowerCase();
63
+
64
+ const isProtected =
65
+ normalizedFile.includes('src/orchestrator/rulez.ts') ||
66
+ normalizedFile.includes('src/orchestrator/sahoo-gateway.ts') ||
67
+ normalizedFile.includes('src/tests/run-tests.ts') ||
68
+ resolvedBaseName === 'package.json' ||
69
+ resolvedBaseName === '.env';
70
+
71
+ if (isProtected) {
72
+ return {
73
+ allowed: false,
74
+ exitCode: 2,
75
+ message: `Blocked by RuleZ: Modification of safety harness or environment configurations (${filePath}) is strictly prohibited.`
76
+ };
77
+ }
78
+
79
+ // 2. Sandbox isolation check: resolved path must be within the workspace root
80
+ const resolvedTarget = path.resolve(filePath);
81
+ const resolvedRoot = path.resolve(process.cwd());
82
+ const relativePath = path.relative(resolvedRoot, resolvedTarget);
83
+ const isOutside = relativePath.startsWith('..') || path.isAbsolute(relativePath);
84
+
85
+ if (isOutside) {
86
+ return {
87
+ allowed: false,
88
+ exitCode: 2,
89
+ message: `Blocked by RuleZ: Path '${filePath}' resolves outside the workspace sandbox.`
90
+ };
91
+ }
92
+
93
+ // 2. Prevent dynamic execution (eval / Function)
94
+ if (/\beval\s*\(/i.test(content) || /\bnew\s+Function\s*\(/i.test(content)) {
95
+ return {
96
+ allowed: false,
97
+ exitCode: 2,
98
+ message: `Blocked by RuleZ: Use of dynamic code execution (eval() or new Function()) is banned.`
99
+ };
100
+ }
101
+
102
+ // 3. Prevent hardcoding secrets/credentials
103
+ for (const pattern of SECRETS_PATTERNS) {
104
+ if (pattern.test(content)) {
105
+ return {
106
+ allowed: false,
107
+ exitCode: 2,
108
+ message: `Blocked by RuleZ: Potential hardcoded secret or API key pattern detected in changes.`
109
+ };
110
+ }
111
+ }
112
+
113
+ return {
114
+ allowed: true,
115
+ exitCode: 0,
116
+ message: 'Allowed by RuleZ'
117
+ };
118
+ }