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.
- package/dist/dashboard/server.js +237 -0
- package/dist/index.js +272 -0
- package/dist/orchestrator/agent-prompts.js +42 -0
- package/dist/orchestrator/autogenesis.js +973 -0
- package/dist/orchestrator/dgm-archive.js +223 -0
- package/dist/orchestrator/event-stream.js +103 -0
- package/dist/orchestrator/fitness-evaluator.js +99 -0
- package/dist/orchestrator/meta-agent.js +421 -0
- package/dist/orchestrator/microagent-registry.js +134 -0
- package/dist/orchestrator/mutation-strategies.js +174 -0
- package/dist/orchestrator/prompt-benchmark.js +102 -0
- package/dist/orchestrator/prompt-optimizer.js +169 -0
- package/dist/orchestrator/refactor-scanner.js +222 -0
- package/dist/orchestrator/research-manager.js +104 -0
- package/dist/orchestrator/rulez.js +135 -0
- package/dist/orchestrator/sahoo-gateway.js +261 -0
- package/dist/orchestrator/state-manager.js +121 -0
- package/dist/orchestrator/task-agent.js +444 -0
- package/dist/orchestrator/telegram-bot.js +374 -0
- package/dist/orchestrator/types.js +2 -0
- package/dist/tests/dynamic/dependencies.test.js +37 -0
- package/dist/tests/dynamic/dummy.test.js +7 -0
- package/dist/tests/dynamic/fuzzy-patch.test.js +68 -0
- package/dist/tests/dynamic/indexer.test.js +60 -0
- package/dist/tests/dynamic/openhands.test.js +83 -0
- package/dist/tests/dynamic/skills.test.js +88 -0
- package/dist/tests/run-tests.js +294 -0
- package/dist/tools/diff-tools.js +24 -0
- package/dist/tools/file-tools.js +191 -0
- package/dist/tools/indexer.js +301 -0
- package/dist/tools/math-helper.js +6 -0
- package/dist/tools/repo-map.js +122 -0
- package/dist/tools/search-tools.js +271 -0
- package/dist/tools/shell-tools.js +75 -0
- package/dist/tools/skills.js +122 -0
- package/dist/tools/tui-tools.js +82 -0
- package/docs/AI_Arch_Opt_Anti_Gaming.md +227 -0
- package/docs/AI_Self_Improvement_Safety.md +457 -0
- package/docs/Anthropic AI Agents_ Capabilities and Concerns.md +134 -0
- package/docs/Auto_ClosedLoop_AI_Agent.md +415 -0
- package/docs/Autonomous AI Agents_ Closing the Loop.docx +0 -0
- package/docs/Secure_AI_Sandbox_Framework.md +358 -0
- package/docs/skills/add-file-existence-check-utility.json +9 -0
- package/docs/skills/add-utility-function-for-file-existence-check.json +9 -0
- package/docs/skills/add-utility-function-to-module.json +9 -0
- package/docs/skills/extract-command-runner-utility.json +9 -0
- package/docs/skills/file-existence-check-utility.json +9 -0
- package/package.json +36 -0
- package/src/dashboard/public/index.css +1334 -0
- package/src/dashboard/public/index.html +385 -0
- package/src/dashboard/public/index.js +1059 -0
- package/src/dashboard/server.ts +209 -0
- package/src/index.ts +256 -0
- package/src/orchestrator/agent-prompts.ts +43 -0
- package/src/orchestrator/autogenesis.ts +1078 -0
- package/src/orchestrator/dgm-archive.ts +257 -0
- package/src/orchestrator/event-stream.ts +90 -0
- package/src/orchestrator/fitness-evaluator.ts +154 -0
- package/src/orchestrator/meta-agent.ts +434 -0
- package/src/orchestrator/microagent-registry.ts +115 -0
- package/src/orchestrator/microagents/git-helper.md +11 -0
- package/src/orchestrator/microagents/test-fixer.md +10 -0
- package/src/orchestrator/microagents/typescript-expert.md +11 -0
- package/src/orchestrator/mutation-strategies.ts +214 -0
- package/src/orchestrator/research-manager.ts +88 -0
- package/src/orchestrator/rulez.ts +118 -0
- package/src/orchestrator/sahoo-gateway.ts +300 -0
- package/src/orchestrator/state-manager.ts +161 -0
- package/src/orchestrator/system-prompt.txt +1 -0
- package/src/orchestrator/task-agent.ts +461 -0
- package/src/orchestrator/telegram-bot.ts +358 -0
- package/src/tests/dynamic/dependencies.test.ts +48 -0
- package/src/tests/dynamic/dummy.test.ts +4 -0
- package/src/tests/dynamic/fuzzy-patch.test.ts +42 -0
- package/src/tests/dynamic/indexer.test.ts +31 -0
- package/src/tests/dynamic/openhands.test.ts +59 -0
- package/src/tests/dynamic/skills.test.ts +63 -0
- package/src/tests/run-tests.ts +296 -0
- package/src/tools/diff-tools.ts +27 -0
- package/src/tools/file-tools.ts +187 -0
- package/src/tools/indexer.ts +325 -0
- package/src/tools/repo-map.ts +96 -0
- package/src/tools/search-tools.ts +258 -0
- package/src/tools/shell-tools.ts +90 -0
- package/src/tools/skills.ts +101 -0
- package/src/tools/tui-tools.ts +87 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ResearchManager = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
class ResearchManager {
|
|
40
|
+
static session = null;
|
|
41
|
+
static logPath = path.join(process.cwd(), 'research-log.json');
|
|
42
|
+
static startSession(task, effort) {
|
|
43
|
+
this.session = {
|
|
44
|
+
taskId: `task-${Date.now()}`,
|
|
45
|
+
task,
|
|
46
|
+
startedAt: new Date().toISOString(),
|
|
47
|
+
status: 'running',
|
|
48
|
+
effort,
|
|
49
|
+
decisions: []
|
|
50
|
+
};
|
|
51
|
+
this.logDecision('session_start', `Starting active research session for task: "${task}"`, 'info');
|
|
52
|
+
this.saveSession();
|
|
53
|
+
}
|
|
54
|
+
static logDecision(phase, action, result, details) {
|
|
55
|
+
if (!this.session)
|
|
56
|
+
return;
|
|
57
|
+
this.session.decisions.push({
|
|
58
|
+
timestamp: new Date().toISOString(),
|
|
59
|
+
phase,
|
|
60
|
+
action,
|
|
61
|
+
result,
|
|
62
|
+
details
|
|
63
|
+
});
|
|
64
|
+
this.saveSession();
|
|
65
|
+
}
|
|
66
|
+
static endSession(status) {
|
|
67
|
+
if (!this.session)
|
|
68
|
+
return;
|
|
69
|
+
this.session.status = status;
|
|
70
|
+
this.session.endedAt = new Date().toISOString();
|
|
71
|
+
this.logDecision('session_end', `Session ended with status: ${status}`, 'info');
|
|
72
|
+
this.saveSession();
|
|
73
|
+
this.session = null;
|
|
74
|
+
}
|
|
75
|
+
static saveSession() {
|
|
76
|
+
if (!this.session)
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
let sessions = [];
|
|
80
|
+
if (fs.existsSync(this.logPath)) {
|
|
81
|
+
try {
|
|
82
|
+
sessions = JSON.parse(fs.readFileSync(this.logPath, 'utf-8'));
|
|
83
|
+
}
|
|
84
|
+
catch (e) { }
|
|
85
|
+
}
|
|
86
|
+
const index = sessions.findIndex(s => s.taskId === this.session.taskId);
|
|
87
|
+
if (index !== -1) {
|
|
88
|
+
sessions[index] = this.session;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
sessions.push(this.session);
|
|
92
|
+
}
|
|
93
|
+
// Keep last 10 sessions to save space
|
|
94
|
+
if (sessions.length > 10) {
|
|
95
|
+
sessions.shift();
|
|
96
|
+
}
|
|
97
|
+
fs.writeFileSync(this.logPath, JSON.stringify(sessions, null, 2), 'utf-8');
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
console.error('[ResearchManager] Failed to write research log:', err);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
exports.ResearchManager = ResearchManager;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.checkCommand = checkCommand;
|
|
37
|
+
exports.checkFileEdit = checkFileEdit;
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
// Banned command substrings
|
|
40
|
+
const BANNED_COMMAND_PATTERNS = [
|
|
41
|
+
/\brm\b\s+-[rf]{1,2}\s+\//, // rm -rf /
|
|
42
|
+
/\brm\b\s+-[rf]{1,2}\s+\./, // rm -rf .
|
|
43
|
+
/\brm\b\s+-[rf]{1,2}\s+([A-Za-z]:)?\\/, // Windows root deletes
|
|
44
|
+
/\bformat\b/i, // disk formats
|
|
45
|
+
/\bgit\b.*\bpush\b.*\b--force\b/, // force pushes
|
|
46
|
+
/\bgit\b.*\bpush\b/, // any direct push to remote
|
|
47
|
+
/\bchmod\b\s+777/, // unsafe permissions elevation
|
|
48
|
+
/\bchown\b/, // ownership tampering
|
|
49
|
+
/(\bdrop\b|\balter\b)\s+database/i // raw database drops
|
|
50
|
+
];
|
|
51
|
+
// Secrets patterns (e.g. tp- tokens, standard slack tokens, etc)
|
|
52
|
+
const SECRETS_PATTERNS = [
|
|
53
|
+
/tp-[a-zA-Z0-9]{32,}/, // MiMo tp- Token pattern
|
|
54
|
+
/sk-[a-zA-Z0-9]{20,}/, // standard OpenAI/Anthropic keys
|
|
55
|
+
/API_KEY\s*=\s*['"][a-zA-Z0-9_-]{16,}['"]/i,
|
|
56
|
+
/PASSWORD\s*=\s*['"][a-zA-Z0-9_-]{8,}['"]/i
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Checks if a command string is allowed under RuleZ policies.
|
|
60
|
+
*/
|
|
61
|
+
function checkCommand(commandStr) {
|
|
62
|
+
const normalizedCmd = commandStr.trim();
|
|
63
|
+
// 1. Check for banned command patterns
|
|
64
|
+
for (const pattern of BANNED_COMMAND_PATTERNS) {
|
|
65
|
+
if (pattern.test(normalizedCmd)) {
|
|
66
|
+
return {
|
|
67
|
+
allowed: false,
|
|
68
|
+
exitCode: 2,
|
|
69
|
+
message: `Blocked by RuleZ: Command violates security policy (matches pattern: ${pattern.toString()})`
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// 2. Safe commands allowed
|
|
74
|
+
return {
|
|
75
|
+
allowed: true,
|
|
76
|
+
exitCode: 0,
|
|
77
|
+
message: 'Allowed by RuleZ'
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Checks if a file edit or write is allowed under RuleZ policies.
|
|
82
|
+
*/
|
|
83
|
+
function checkFileEdit(filePath, content) {
|
|
84
|
+
// 1. Protected files lockout (Campbell Safeguard Policy)
|
|
85
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
86
|
+
const normalizedFile = normalizedPath.toLowerCase();
|
|
87
|
+
const resolvedBaseName = path.basename(filePath).toLowerCase();
|
|
88
|
+
const isProtected = normalizedFile.includes('src/orchestrator/rulez.ts') ||
|
|
89
|
+
normalizedFile.includes('src/orchestrator/sahoo-gateway.ts') ||
|
|
90
|
+
normalizedFile.includes('src/tests/run-tests.ts') ||
|
|
91
|
+
resolvedBaseName === 'package.json' ||
|
|
92
|
+
resolvedBaseName === '.env';
|
|
93
|
+
if (isProtected) {
|
|
94
|
+
return {
|
|
95
|
+
allowed: false,
|
|
96
|
+
exitCode: 2,
|
|
97
|
+
message: `Blocked by RuleZ: Modification of safety harness or environment configurations (${filePath}) is strictly prohibited.`
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// 2. Sandbox isolation check: resolved path must be within the workspace root
|
|
101
|
+
const resolvedTarget = path.resolve(filePath);
|
|
102
|
+
const resolvedRoot = path.resolve(process.cwd());
|
|
103
|
+
const relativePath = path.relative(resolvedRoot, resolvedTarget);
|
|
104
|
+
const isOutside = relativePath.startsWith('..') || path.isAbsolute(relativePath);
|
|
105
|
+
if (isOutside) {
|
|
106
|
+
return {
|
|
107
|
+
allowed: false,
|
|
108
|
+
exitCode: 2,
|
|
109
|
+
message: `Blocked by RuleZ: Path '${filePath}' resolves outside the workspace sandbox.`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// 2. Prevent dynamic execution (eval / Function)
|
|
113
|
+
if (/\beval\s*\(/i.test(content) || /\bnew\s+Function\s*\(/i.test(content)) {
|
|
114
|
+
return {
|
|
115
|
+
allowed: false,
|
|
116
|
+
exitCode: 2,
|
|
117
|
+
message: `Blocked by RuleZ: Use of dynamic code execution (eval() or new Function()) is banned.`
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
// 3. Prevent hardcoding secrets/credentials
|
|
121
|
+
for (const pattern of SECRETS_PATTERNS) {
|
|
122
|
+
if (pattern.test(content)) {
|
|
123
|
+
return {
|
|
124
|
+
allowed: false,
|
|
125
|
+
exitCode: 2,
|
|
126
|
+
message: `Blocked by RuleZ: Potential hardcoded secret or API key pattern detected in changes.`
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
allowed: true,
|
|
132
|
+
exitCode: 0,
|
|
133
|
+
message: 'Allowed by RuleZ'
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateSemanticDrift = calculateSemanticDrift;
|
|
4
|
+
exports.calculateLexicalDrift = calculateLexicalDrift;
|
|
5
|
+
exports.calculateStructuralDrift = calculateStructuralDrift;
|
|
6
|
+
exports.calculateDistributionalDrift = calculateDistributionalDrift;
|
|
7
|
+
exports.checkSafetyConstraints = checkSafetyConstraints;
|
|
8
|
+
exports.evaluateSahoo = evaluateSahoo;
|
|
9
|
+
/**
|
|
10
|
+
* Helper: Computes character trigrams and returns a map of frequencies.
|
|
11
|
+
*/
|
|
12
|
+
function getTrigramFreq(str) {
|
|
13
|
+
const map = new Map();
|
|
14
|
+
if (str.length < 3)
|
|
15
|
+
return map;
|
|
16
|
+
for (let i = 0; i <= str.length - 3; i++) {
|
|
17
|
+
const trigram = str.substring(i, i + 3);
|
|
18
|
+
map.set(trigram, (map.get(trigram) || 0) + 1);
|
|
19
|
+
}
|
|
20
|
+
return map;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Calculates Semantic Drift using Trigram Cosine Similarity.
|
|
24
|
+
* Cosine distance = 1 - Cosine Similarity.
|
|
25
|
+
*/
|
|
26
|
+
function calculateSemanticDrift(before, after) {
|
|
27
|
+
const tBefore = getTrigramFreq(before);
|
|
28
|
+
const tAfter = getTrigramFreq(after);
|
|
29
|
+
if (tBefore.size === 0 && tAfter.size === 0)
|
|
30
|
+
return 0;
|
|
31
|
+
// Calculate dot product and magnitudes
|
|
32
|
+
let dotProduct = 0;
|
|
33
|
+
tBefore.forEach((val, key) => {
|
|
34
|
+
if (tAfter.has(key)) {
|
|
35
|
+
dotProduct += val * (tAfter.get(key) || 0);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
let magBefore = 0;
|
|
39
|
+
tBefore.forEach(val => magBefore += val * val);
|
|
40
|
+
magBefore = Math.sqrt(magBefore);
|
|
41
|
+
let magAfter = 0;
|
|
42
|
+
tAfter.forEach(val => magAfter += val * val);
|
|
43
|
+
magAfter = Math.sqrt(magAfter);
|
|
44
|
+
if (magBefore === 0 || magAfter === 0)
|
|
45
|
+
return 1.0;
|
|
46
|
+
const similarity = Math.min(Math.max(dotProduct / (magBefore * magAfter), -1.0), 1.0);
|
|
47
|
+
const distance = 1.0 - similarity;
|
|
48
|
+
return Math.abs(distance) < 1e-12 ? 0 : distance; // Cosine distance
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Calculates Lexical Drift using normalized Levenshtein edit distance.
|
|
52
|
+
*/
|
|
53
|
+
function calculateLexicalDrift(before, after) {
|
|
54
|
+
if (before === after)
|
|
55
|
+
return 0;
|
|
56
|
+
if (before.length === 0)
|
|
57
|
+
return 1.0;
|
|
58
|
+
if (after.length === 0)
|
|
59
|
+
return 1.0;
|
|
60
|
+
const matrix = [];
|
|
61
|
+
const bLen = before.length;
|
|
62
|
+
const aLen = after.length;
|
|
63
|
+
// For memory optimization under large strings, cap calculation length
|
|
64
|
+
const maxLen = 1000;
|
|
65
|
+
const sBefore = before.substring(0, maxLen);
|
|
66
|
+
const sAfter = after.substring(0, maxLen);
|
|
67
|
+
const n = sBefore.length;
|
|
68
|
+
const m = sAfter.length;
|
|
69
|
+
for (let i = 0; i <= n; i++) {
|
|
70
|
+
matrix[i] = [i];
|
|
71
|
+
}
|
|
72
|
+
for (let j = 0; j <= m; j++) {
|
|
73
|
+
matrix[0][j] = j;
|
|
74
|
+
}
|
|
75
|
+
for (let i = 1; i <= n; i++) {
|
|
76
|
+
for (let j = 1; j <= m; j++) {
|
|
77
|
+
if (sBefore[i - 1] === sAfter[j - 1]) {
|
|
78
|
+
matrix[i][j] = matrix[i - 1][j - 1];
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
|
|
82
|
+
matrix[i][j - 1] + 1, // insertion
|
|
83
|
+
matrix[i - 1][j] + 1 // deletion
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return matrix[n][m] / Math.max(n, m);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Calculates Structural Drift: normalized line and size differences.
|
|
92
|
+
*/
|
|
93
|
+
function calculateStructuralDrift(before, after) {
|
|
94
|
+
const linesBefore = before.split('\n').length;
|
|
95
|
+
const linesAfter = after.split('\n').length;
|
|
96
|
+
const sizeBefore = before.length;
|
|
97
|
+
const sizeAfter = after.length;
|
|
98
|
+
const lineDiff = Math.abs(linesAfter - linesBefore) / (Math.max(linesBefore, 1));
|
|
99
|
+
const sizeDiff = Math.abs(sizeAfter - sizeBefore) / (Math.max(sizeBefore, 1));
|
|
100
|
+
return Math.min((lineDiff + sizeDiff) / 2, 1.0);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Calculates Distributional Drift by evaluating changes in JavaScript/TypeScript keyword frequencies.
|
|
104
|
+
*/
|
|
105
|
+
function calculateDistributionalDrift(before, after) {
|
|
106
|
+
const keywords = ['const', 'let', 'var', 'if', 'else', 'for', 'while', 'function', 'class', 'import', 'export', 'return', 'await', 'async'];
|
|
107
|
+
function getKeywordFreq(str) {
|
|
108
|
+
const map = new Map();
|
|
109
|
+
const tokens = str.split(/\W+/);
|
|
110
|
+
tokens.forEach(tok => {
|
|
111
|
+
if (keywords.includes(tok)) {
|
|
112
|
+
map.set(tok, (map.get(tok) || 0) + 1);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
return map;
|
|
116
|
+
}
|
|
117
|
+
const freqBefore = getKeywordFreq(before);
|
|
118
|
+
const freqAfter = getKeywordFreq(after);
|
|
119
|
+
let totalDiff = 0;
|
|
120
|
+
let totalKeys = 0;
|
|
121
|
+
keywords.forEach(kw => {
|
|
122
|
+
const countBefore = freqBefore.get(kw) || 0;
|
|
123
|
+
const countAfter = freqAfter.get(kw) || 0;
|
|
124
|
+
totalDiff += Math.abs(countAfter - countBefore);
|
|
125
|
+
totalKeys += countBefore + countAfter;
|
|
126
|
+
});
|
|
127
|
+
if (totalKeys === 0)
|
|
128
|
+
return 0;
|
|
129
|
+
return Math.min(totalDiff / totalKeys, 1.0);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Safety Constraints Check for CPS (Constraint Preservation Score).
|
|
133
|
+
*/
|
|
134
|
+
function checkSafetyConstraints(filePath, content, compileSuccess, testsSuccess) {
|
|
135
|
+
const failedList = [];
|
|
136
|
+
let satisfied = 0;
|
|
137
|
+
const K = 5; // Number of total constraints
|
|
138
|
+
// Constraint 1: Compiles successfully
|
|
139
|
+
if (compileSuccess) {
|
|
140
|
+
satisfied++;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
failedList.push('CompilationFailure');
|
|
144
|
+
}
|
|
145
|
+
// Constraint 2: Tests pass
|
|
146
|
+
if (testsSuccess) {
|
|
147
|
+
satisfied++;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
failedList.push('TestExecutionFailure');
|
|
151
|
+
}
|
|
152
|
+
// Constraint 3: No dynamic eval / Function execution in code
|
|
153
|
+
const hasEval = /\beval\s*\(/i.test(content) || /\bnew\s+Function\s*\(/i.test(content);
|
|
154
|
+
if (!hasEval) {
|
|
155
|
+
satisfied++;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
failedList.push('DynamicCodeExecutionViolation');
|
|
159
|
+
}
|
|
160
|
+
// Constraint 4: No hardcoded secrets
|
|
161
|
+
const secretPatterns = [
|
|
162
|
+
/tp-[a-zA-Z0-9]{32,}/, // MiMo Token pattern
|
|
163
|
+
/sk-[a-zA-Z0-9]{20,}/ // standard key patterns
|
|
164
|
+
];
|
|
165
|
+
const hasSecrets = secretPatterns.some(pat => pat.test(content));
|
|
166
|
+
if (!hasSecrets) {
|
|
167
|
+
satisfied++;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
failedList.push('SecretLeakViolation');
|
|
171
|
+
}
|
|
172
|
+
// Constraint 5: Path safety (inside workspace)
|
|
173
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
174
|
+
const isSafePath = !normalizedPath.includes('../') && !normalizedPath.includes('..\\');
|
|
175
|
+
if (isSafePath) {
|
|
176
|
+
satisfied++;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
failedList.push('PathSafetyViolation');
|
|
180
|
+
}
|
|
181
|
+
return {
|
|
182
|
+
score: satisfied / K,
|
|
183
|
+
failedList
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Evaluates a codebase mutation against the SAHOO Safeguarding Policy.
|
|
188
|
+
*/
|
|
189
|
+
function evaluateSahoo(filePath, beforeContent, afterContent, compileSuccess, testsSuccess, historicalScores = [1.0] // Default history to prevent division by zero
|
|
190
|
+
) {
|
|
191
|
+
// 1. Calculate individual drifts
|
|
192
|
+
const semantic = calculateSemanticDrift(beforeContent, afterContent);
|
|
193
|
+
const lexical = calculateLexicalDrift(beforeContent, afterContent);
|
|
194
|
+
const structural = calculateStructuralDrift(beforeContent, afterContent);
|
|
195
|
+
const distributional = calculateDistributionalDrift(beforeContent, afterContent);
|
|
196
|
+
// 2. Compute Goal Drift Index (GDI)
|
|
197
|
+
// GDI = 0.38*semantic + 0.12*lexical + 0.21*structural + 0.29*distributional
|
|
198
|
+
const gdi = (0.38 * semantic) + (0.12 * lexical) + (0.21 * structural) + (0.29 * distributional);
|
|
199
|
+
// 3. Compute Constraint Preservation Score (CPS)
|
|
200
|
+
const { score: cps, failedList } = checkSafetyConstraints(filePath, afterContent, compileSuccess, testsSuccess);
|
|
201
|
+
// 4. Compute Regression Risk (R_c)
|
|
202
|
+
// Pr(Q_c < Q_max - delta)
|
|
203
|
+
// We model Q_c as the current CPS score. Q_max is the highest historical score (typically 1.0).
|
|
204
|
+
// If historical performance is low, we quantify risk mathematically.
|
|
205
|
+
const qMax = Math.max(...historicalScores, 1.0);
|
|
206
|
+
const currentQ = cps;
|
|
207
|
+
// Calculate variance of historical scores
|
|
208
|
+
const mean = historicalScores.reduce((a, b) => a + b, 0) / historicalScores.length;
|
|
209
|
+
const variance = historicalScores.reduce((a, b) => a + Math.pow(b - mean, 2), 0) / historicalScores.length;
|
|
210
|
+
const stdDev = Math.max(Math.sqrt(variance), 0.05); // Min standard dev of 5%
|
|
211
|
+
// Regression Risk estimate using Gaussian Cumulative Distribution proxy:
|
|
212
|
+
// Z = (currentQ - qMax) / stdDev
|
|
213
|
+
// R_c = P(Z < 0)
|
|
214
|
+
const z = (currentQ - qMax) / stdDev;
|
|
215
|
+
let regressionRisk = 0.5; // default if z == 0
|
|
216
|
+
if (z < 0) {
|
|
217
|
+
// Standard approximation of normal CDF
|
|
218
|
+
regressionRisk = 1.0 - (1.0 / (1.0 + Math.exp(-1.6 * z)));
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
regressionRisk = 1.0 / (1.0 + Math.exp(1.6 * z));
|
|
222
|
+
}
|
|
223
|
+
const metrics = {
|
|
224
|
+
semanticDrift: semantic,
|
|
225
|
+
lexicalDrift: lexical,
|
|
226
|
+
structuralDrift: structural,
|
|
227
|
+
distributionalDrift: distributional,
|
|
228
|
+
goalDriftIndex: gdi,
|
|
229
|
+
constraintPreservationScore: cps,
|
|
230
|
+
regressionRisk: regressionRisk
|
|
231
|
+
};
|
|
232
|
+
// Halting policies:
|
|
233
|
+
// 1. GDI Threshold: Halts execution if GDI > 0.440
|
|
234
|
+
if (gdi > 0.440) {
|
|
235
|
+
return {
|
|
236
|
+
passed: false,
|
|
237
|
+
metrics,
|
|
238
|
+
reason: `Blocked by SAHOO: Goal Drift Index exceeded threshold (${gdi.toFixed(3)} > 0.440)`
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// 2. CPS Threshold: Halts execution if CPS < 1.0 (Zero-tolerance for safety violations)
|
|
242
|
+
if (cps < 1.0) {
|
|
243
|
+
return {
|
|
244
|
+
passed: false,
|
|
245
|
+
metrics,
|
|
246
|
+
reason: `Blocked by SAHOO: Constraint Preservation Score fell below 1.0 (Violations: ${failedList.join(', ')})`
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
// 3. Regression Risk threshold: Halt if risk > 0.8
|
|
250
|
+
if (regressionRisk > 0.80) {
|
|
251
|
+
return {
|
|
252
|
+
passed: false,
|
|
253
|
+
metrics,
|
|
254
|
+
reason: `Blocked by SAHOO: Regression Risk too high (${(regressionRisk * 100).toFixed(1)}% > 80%)`
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
return {
|
|
258
|
+
passed: true,
|
|
259
|
+
metrics
|
|
260
|
+
};
|
|
261
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.getEvolutionState = getEvolutionState;
|
|
37
|
+
exports.updateEvolutionState = updateEvolutionState;
|
|
38
|
+
exports.appendHistory = appendHistory;
|
|
39
|
+
exports.appendArchive = appendArchive;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const statePath = path.join(process.cwd(), 'evolution-state.json');
|
|
43
|
+
const defaultState = {
|
|
44
|
+
status: 'idle',
|
|
45
|
+
currentCycle: 0,
|
|
46
|
+
maxCycles: 0,
|
|
47
|
+
tokenBudget: 500000,
|
|
48
|
+
tokensUsed: { input: 0, output: 0, total: 0 },
|
|
49
|
+
lastUpdated: new Date().toISOString(),
|
|
50
|
+
currentTask: null,
|
|
51
|
+
lastRefactorProposal: null,
|
|
52
|
+
lastRefactorResult: null,
|
|
53
|
+
lastPromptOptimization: null,
|
|
54
|
+
history: [],
|
|
55
|
+
archive: [],
|
|
56
|
+
currentFitness: 0,
|
|
57
|
+
bestFitness: 0,
|
|
58
|
+
dgmPopulationSize: 0,
|
|
59
|
+
dgmBestEntryId: null
|
|
60
|
+
};
|
|
61
|
+
function getEvolutionState() {
|
|
62
|
+
if (!fs.existsSync(statePath)) {
|
|
63
|
+
return defaultState;
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const raw = fs.readFileSync(statePath, 'utf-8');
|
|
67
|
+
return JSON.parse(raw);
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
return defaultState;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const event_stream_1 = require("./event-stream");
|
|
74
|
+
function updateEvolutionState(update) {
|
|
75
|
+
const currentState = getEvolutionState();
|
|
76
|
+
const tokensUsed = update.tokensUsed
|
|
77
|
+
? { ...currentState.tokensUsed, ...update.tokensUsed }
|
|
78
|
+
: currentState.tokensUsed;
|
|
79
|
+
const merged = {
|
|
80
|
+
...currentState,
|
|
81
|
+
...update,
|
|
82
|
+
tokensUsed,
|
|
83
|
+
lastUpdated: new Date().toISOString()
|
|
84
|
+
};
|
|
85
|
+
merged.tokensUsed.total = merged.tokensUsed.input + merged.tokensUsed.output;
|
|
86
|
+
// Log status transitions to EventStream
|
|
87
|
+
if (update.status && update.status !== currentState.status) {
|
|
88
|
+
event_stream_1.EventStream.getInstance().publish('system', 'log', 'StateTransition', `System status changed from '${currentState.status}' to '${update.status}'`);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
fs.writeFileSync(statePath, JSON.stringify(merged, null, 2), 'utf-8');
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error('Failed to write evolution state file:', err);
|
|
95
|
+
}
|
|
96
|
+
return merged;
|
|
97
|
+
}
|
|
98
|
+
function appendHistory(item) {
|
|
99
|
+
const state = getEvolutionState();
|
|
100
|
+
const historyItem = {
|
|
101
|
+
...item,
|
|
102
|
+
time: new Date().toISOString()
|
|
103
|
+
};
|
|
104
|
+
const updatedHistory = [...state.history, historyItem];
|
|
105
|
+
if (updatedHistory.length > 50) {
|
|
106
|
+
updatedHistory.shift();
|
|
107
|
+
}
|
|
108
|
+
updateEvolutionState({ history: updatedHistory });
|
|
109
|
+
}
|
|
110
|
+
function appendArchive(item) {
|
|
111
|
+
const state = getEvolutionState();
|
|
112
|
+
const archiveItem = {
|
|
113
|
+
...item,
|
|
114
|
+
timestamp: new Date().toISOString()
|
|
115
|
+
};
|
|
116
|
+
const updatedArchive = [...(state.archive || []), archiveItem];
|
|
117
|
+
if (updatedArchive.length > 10) {
|
|
118
|
+
updatedArchive.shift();
|
|
119
|
+
}
|
|
120
|
+
updateEvolutionState({ archive: updatedArchive });
|
|
121
|
+
}
|