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,88 @@
|
|
|
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.run = run;
|
|
37
|
+
const skills_1 = require("../../tools/skills");
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
async function run() {
|
|
41
|
+
console.log(" --> Running Skill Registry tests...");
|
|
42
|
+
const workspaceRoot = process.cwd();
|
|
43
|
+
const skillsDir = path.join(workspaceRoot, 'docs', 'skills');
|
|
44
|
+
const testSkillFile = path.join(skillsDir, 'test-reusable-skill.json');
|
|
45
|
+
// Clean up previous test files if any
|
|
46
|
+
if (fs.existsSync(testSkillFile)) {
|
|
47
|
+
fs.unlinkSync(testSkillFile);
|
|
48
|
+
}
|
|
49
|
+
// 1. Mock inputs
|
|
50
|
+
const mockTask = "Add a checkFileExists utility inside file-tools.ts";
|
|
51
|
+
const mockDiff = `diff --git a/src/tools/file-tools.ts b/src/tools/file-tools.ts
|
|
52
|
+
index e69de29..b2a8d11 100644
|
|
53
|
+
--- a/src/tools/file-tools.ts
|
|
54
|
+
+++ b/src/tools/file-tools.ts
|
|
55
|
+
@@ -1 +1,5 @@
|
|
56
|
+
+export function checkFileExists(path: string): boolean {
|
|
57
|
+
+ return fs.existsSync(path);
|
|
58
|
+
+}
|
|
59
|
+
`;
|
|
60
|
+
// 2. Extract and Save
|
|
61
|
+
await (0, skills_1.extractAndSaveSkill)(mockTask, mockDiff);
|
|
62
|
+
// Find any generated json files
|
|
63
|
+
if (!fs.existsSync(skillsDir)) {
|
|
64
|
+
throw new Error("skills directory was not created!");
|
|
65
|
+
}
|
|
66
|
+
const files = fs.readdirSync(skillsDir).filter(f => f.endsWith('.json'));
|
|
67
|
+
if (files.length === 0) {
|
|
68
|
+
throw new Error("No playbooks were written by extractAndSaveSkill!");
|
|
69
|
+
}
|
|
70
|
+
console.log(` --> Created playbooks: ${files.join(', ')}`);
|
|
71
|
+
// 3. Summarize
|
|
72
|
+
const summaries = (0, skills_1.getSkillsSummary)();
|
|
73
|
+
console.log(" --> Playbook summaries:\n", summaries);
|
|
74
|
+
if (summaries === 'No custom development skills recorded yet.') {
|
|
75
|
+
throw new Error("getSkillsSummary returned default empty statement despite files present.");
|
|
76
|
+
}
|
|
77
|
+
// Clean up mock output to keep it clean, but wait, keeping it is also fine since git ignores or tracks.
|
|
78
|
+
// Actually, let's keep one test playbook for verification and delete any temporary ones if needed.
|
|
79
|
+
// Let's delete the temporary test file.
|
|
80
|
+
const testFiles = files.filter(f => f.includes('reusable-skill') || f.includes('exists'));
|
|
81
|
+
for (const f of testFiles) {
|
|
82
|
+
try {
|
|
83
|
+
fs.unlinkSync(path.join(skillsDir, f));
|
|
84
|
+
}
|
|
85
|
+
catch (e) { }
|
|
86
|
+
}
|
|
87
|
+
console.log(" --> Skill Registry tests passed!");
|
|
88
|
+
}
|
|
@@ -0,0 +1,294 @@
|
|
|
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
|
+
const path = __importStar(require("path"));
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const shell_tools_1 = require("../tools/shell-tools");
|
|
39
|
+
const fileTools = __importStar(require("../tools/file-tools"));
|
|
40
|
+
const rulez = __importStar(require("../orchestrator/rulez"));
|
|
41
|
+
const sahoo = __importStar(require("../orchestrator/sahoo-gateway"));
|
|
42
|
+
const repo_map_1 = require("../tools/repo-map");
|
|
43
|
+
const search_tools_1 = require("../tools/search-tools");
|
|
44
|
+
const autogenesis_1 = require("../orchestrator/autogenesis");
|
|
45
|
+
async function runTest(name, fn) {
|
|
46
|
+
console.log(`\x1b[36m[Test]\x1b[0m Running: ${name}...`);
|
|
47
|
+
try {
|
|
48
|
+
await fn();
|
|
49
|
+
console.log(`\x1b[32m[Pass]\x1b[0m ${name}\n`);
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
console.error(`\x1b[31m[Fail]\x1b[0m ${name}`);
|
|
53
|
+
console.error(err.stack || err.message);
|
|
54
|
+
console.error('');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function main() {
|
|
59
|
+
console.log('\x1b[35m=== RUNNING BINARY ASSERTION TESTS ===\x1b[0m\n');
|
|
60
|
+
// Test 1: TypeScript Compilation
|
|
61
|
+
await runTest('TypeScript Compilation Check', async () => {
|
|
62
|
+
console.log('Running tsc compilation...');
|
|
63
|
+
const result = await (0, shell_tools_1.runCommand)('npx tsc --noEmit');
|
|
64
|
+
if (result.exitCode !== 0) {
|
|
65
|
+
throw new Error(`TypeScript compilation failed!\nStdout:\n${result.stdout}\nStderr:\n${result.stderr}`);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
// Test 2: File Tools Read/Write/Edit
|
|
69
|
+
await runTest('File Tools Functionality', () => {
|
|
70
|
+
const tempFile = 'temp-test-file.txt';
|
|
71
|
+
const content = 'Line 1\nTarget content here\nLine 3';
|
|
72
|
+
// Test Write
|
|
73
|
+
fileTools.writeFile(tempFile, content);
|
|
74
|
+
// Test Read
|
|
75
|
+
const readBack = fileTools.readFile(tempFile);
|
|
76
|
+
if (readBack !== content) {
|
|
77
|
+
fs.unlinkSync(tempFile);
|
|
78
|
+
throw new Error(`Read content did not match written content.`);
|
|
79
|
+
}
|
|
80
|
+
// Test Edit (Precise replacement)
|
|
81
|
+
fileTools.editFile(tempFile, 'Target content here', 'Replaced content');
|
|
82
|
+
const readAfterEdit = fileTools.readFile(tempFile);
|
|
83
|
+
const expectedContent = 'Line 1\nReplaced content\nLine 3';
|
|
84
|
+
// Clean up
|
|
85
|
+
fs.unlinkSync(tempFile);
|
|
86
|
+
if (readAfterEdit !== expectedContent) {
|
|
87
|
+
throw new Error(`Edit did not replace target content correctly. Got:\n${readAfterEdit}`);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
// Test 3: List Directory
|
|
91
|
+
await runTest('List Directory Tool', () => {
|
|
92
|
+
const items = fileTools.listDir('.');
|
|
93
|
+
const hasSrc = items.some(item => item.name === 'src' && item.isDir);
|
|
94
|
+
const hasPackageJson = items.some(item => item.name === 'package.json' && !item.isDir);
|
|
95
|
+
if (!hasSrc || !hasPackageJson) {
|
|
96
|
+
throw new Error(`Directory listing did not return expected workspace files.`);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
// Test 4: Grep Search Tool
|
|
100
|
+
await runTest('Grep Search Tool', () => {
|
|
101
|
+
const results = fileTools.grepSearch('AutogenesisEngine', 'src');
|
|
102
|
+
if (results.length === 0) {
|
|
103
|
+
throw new Error(`Grep search could not find occurrences of 'AutogenesisEngine' in src directory.`);
|
|
104
|
+
}
|
|
105
|
+
const hasIndexMatch = results.some(res => res.filePath.includes('index.ts'));
|
|
106
|
+
if (!hasIndexMatch) {
|
|
107
|
+
throw new Error(`Grep search missed match in src/index.ts`);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
// Test 5: RuleZ Policy Engine
|
|
111
|
+
await runTest('RuleZ Policy Block and Allow Checks', () => {
|
|
112
|
+
// Unsafe commands
|
|
113
|
+
const blockCmd = rulez.checkCommand('rm -rf /');
|
|
114
|
+
if (blockCmd.allowed || blockCmd.exitCode !== 2) {
|
|
115
|
+
throw new Error(`RuleZ failed to block destructive command 'rm -rf /'.`);
|
|
116
|
+
}
|
|
117
|
+
const blockPush = rulez.checkCommand('git push --force');
|
|
118
|
+
if (blockPush.allowed) {
|
|
119
|
+
throw new Error('RuleZ failed to block git push --force');
|
|
120
|
+
}
|
|
121
|
+
// Safe command
|
|
122
|
+
const allowCmd = rulez.checkCommand('npm run build');
|
|
123
|
+
if (!allowCmd.allowed || allowCmd.exitCode !== 0) {
|
|
124
|
+
throw new Error('RuleZ blocked a safe command npm run build');
|
|
125
|
+
}
|
|
126
|
+
// Unsafe file edit (eval)
|
|
127
|
+
const blockEval = rulez.checkFileEdit('src/test.ts', 'const x = eval("1+1");');
|
|
128
|
+
if (blockEval.allowed || blockEval.exitCode !== 2) {
|
|
129
|
+
throw new Error('RuleZ failed to block file edit containing eval().');
|
|
130
|
+
}
|
|
131
|
+
// Unsafe file edit (secrets)
|
|
132
|
+
const blockSecret = rulez.checkFileEdit('src/secrets.ts', 'const token = "tp-sxbionmkvlslw9t9vnjmuwey6a47cwwnfi6jtd8zcq65bnv1";');
|
|
133
|
+
if (blockSecret.allowed || blockSecret.exitCode !== 2) {
|
|
134
|
+
throw new Error('RuleZ failed to block file edit containing a MiMo token.');
|
|
135
|
+
}
|
|
136
|
+
// Sandbox Path Isolation checks
|
|
137
|
+
const blockRelativeOutside = rulez.checkFileEdit('../outside.txt', 'hello');
|
|
138
|
+
if (blockRelativeOutside.allowed || blockRelativeOutside.exitCode !== 2) {
|
|
139
|
+
throw new Error('RuleZ failed to block file edit outside the workspace (relative path).');
|
|
140
|
+
}
|
|
141
|
+
const blockAbsoluteOutside = rulez.checkFileEdit('C:\\Users\\akara\\outside.txt', 'hello');
|
|
142
|
+
if (blockAbsoluteOutside.allowed || blockAbsoluteOutside.exitCode !== 2) {
|
|
143
|
+
throw new Error('RuleZ failed to block file edit outside the workspace (absolute path).');
|
|
144
|
+
}
|
|
145
|
+
const allowInside = rulez.checkFileEdit('src/tools/math-helper.ts', 'const x = 1;');
|
|
146
|
+
if (!allowInside.allowed || allowInside.exitCode !== 0) {
|
|
147
|
+
throw new Error('RuleZ blocked a safe file edit inside the workspace.');
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
// Test 6: SAHOO Safeguarding Gateway Checks
|
|
151
|
+
await runTest('SAHOO Gateway Drifts and Constraints', () => {
|
|
152
|
+
const beforeCode = 'function calculateSum(a: number, b: number) {\n return a + b;\n}';
|
|
153
|
+
const afterCode = 'function calculateSum(a: number, b: number) {\n return a + b;\n}';
|
|
154
|
+
// Test identical code drift is 0
|
|
155
|
+
const semDriftZero = sahoo.calculateSemanticDrift(beforeCode, afterCode);
|
|
156
|
+
if (semDriftZero !== 0) {
|
|
157
|
+
throw new Error(`Semantic drift for identical strings should be 0, got ${semDriftZero}`);
|
|
158
|
+
}
|
|
159
|
+
// Test different code drift
|
|
160
|
+
const veryDifferent = 'const value = "hello world";\nconsole.log(value);';
|
|
161
|
+
const semDriftDiff = sahoo.calculateSemanticDrift(beforeCode, veryDifferent);
|
|
162
|
+
if (semDriftDiff === 0) {
|
|
163
|
+
throw new Error('Semantic drift for different strings should be non-zero.');
|
|
164
|
+
}
|
|
165
|
+
// Test CPS halts on compilation failure
|
|
166
|
+
const evalFail = sahoo.evaluateSahoo('src/temp.ts', beforeCode, afterCode, false, true);
|
|
167
|
+
if (evalFail.passed) {
|
|
168
|
+
throw new Error('SAHOO should reject changes if compilation failed.');
|
|
169
|
+
}
|
|
170
|
+
// Test CPS halts on eval injection
|
|
171
|
+
const evalWithViolation = sahoo.evaluateSahoo('src/temp.ts', beforeCode, 'const x = eval("5");', true, true);
|
|
172
|
+
if (evalWithViolation.passed) {
|
|
173
|
+
throw new Error('SAHOO should reject changes containing eval dynamic code.');
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
// Test 7: Repository Map Generation
|
|
177
|
+
await runTest('Repository Map Generation Check', () => {
|
|
178
|
+
const repoMap = (0, repo_map_1.generateRepoMap)();
|
|
179
|
+
if (!repoMap) {
|
|
180
|
+
throw new Error('Repository map returned empty output.');
|
|
181
|
+
}
|
|
182
|
+
if (!repoMap.includes('File: src/orchestrator/meta-agent.ts') && !repoMap.includes('File: src/orchestrator/meta-agent')) {
|
|
183
|
+
throw new Error('Repository map is missing expected source files.');
|
|
184
|
+
}
|
|
185
|
+
if (!repoMap.includes('runSelfImprovingTask')) {
|
|
186
|
+
throw new Error('Repository map is missing expected signatures like runSelfImprovingTask.');
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
// Test 8: Web Search Tool Integration
|
|
190
|
+
await runTest('Web Search Tool Integration Check', async () => {
|
|
191
|
+
const results = await (0, search_tools_1.searchWeb)('javascript nodejs');
|
|
192
|
+
if (!results) {
|
|
193
|
+
throw new Error('Web search returned empty output.');
|
|
194
|
+
}
|
|
195
|
+
// Check if it got actual results or a readable connection error
|
|
196
|
+
if (!results.includes('results') && !results.includes('Error')) {
|
|
197
|
+
throw new Error(`Web search output format unexpected: ${results}`);
|
|
198
|
+
}
|
|
199
|
+
console.log(`Web search test output snippet: ${results.substring(0, 150)}...`);
|
|
200
|
+
});
|
|
201
|
+
// Test 9: Autonomous Refactor Proposal Generation Check
|
|
202
|
+
await runTest('Autonomous Refactor Proposal Scan Check', async () => {
|
|
203
|
+
const engine = new autogenesis_1.AutogenesisEngine();
|
|
204
|
+
const proposal = await engine.getAutonomousRefactorProposal();
|
|
205
|
+
if (!proposal.targetFile) {
|
|
206
|
+
throw new Error('Refactoring proposal targetFile is missing.');
|
|
207
|
+
}
|
|
208
|
+
if (!proposal.refactorGoal) {
|
|
209
|
+
throw new Error('Refactoring proposal refactorGoal is missing.');
|
|
210
|
+
}
|
|
211
|
+
console.log(`Scan test proposal generated - Target: ${proposal.targetFile} | Goal: ${proposal.refactorGoal}`);
|
|
212
|
+
});
|
|
213
|
+
// Test 10: Prompt Benchmarking Score Calculation Check
|
|
214
|
+
await runTest('Prompt Benchmarking Score Calculation Check', () => {
|
|
215
|
+
const engine = new autogenesis_1.AutogenesisEngine();
|
|
216
|
+
// Score with zero parameters should be 0
|
|
217
|
+
const zeroScore = engine.calculatePromptScore(0, 0);
|
|
218
|
+
if (zeroScore !== 0) {
|
|
219
|
+
throw new Error(`Expected zero score for 0 time/tokens, got ${zeroScore}`);
|
|
220
|
+
}
|
|
221
|
+
// Score with valid parameters
|
|
222
|
+
const scoreA = engine.calculatePromptScore(10, 100); // 10*0.4 + 100*0.6 = 64 => 100000/64 = 1562.5
|
|
223
|
+
const scoreB = engine.calculatePromptScore(20, 200); // 20*0.4 + 200*0.6 = 128 => 100000/128 = 781.25
|
|
224
|
+
if (Math.abs(scoreA - 1562.5) > 0.01) {
|
|
225
|
+
throw new Error(`Score A calculation incorrect: got ${scoreA}, expected 1562.5`);
|
|
226
|
+
}
|
|
227
|
+
if (Math.abs(scoreB - 781.25) > 0.01) {
|
|
228
|
+
throw new Error(`Score B calculation incorrect: got ${scoreB}, expected 781.25`);
|
|
229
|
+
}
|
|
230
|
+
// A better performance (less time, less tokens) must produce a higher score
|
|
231
|
+
if (scoreA <= scoreB) {
|
|
232
|
+
throw new Error(`Expected scoreA (${scoreA}) to be higher than scoreB (${scoreB})`);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// Test 11: Campbell Regime Write-Protection Policy Check
|
|
236
|
+
await runTest('Campbell Regime Write-Protection Policy Check', () => {
|
|
237
|
+
// Attempt edit of rulez.ts
|
|
238
|
+
const blockRulez = rulez.checkFileEdit('src/orchestrator/rulez.ts', 'const debug = true;');
|
|
239
|
+
if (blockRulez.allowed || blockRulez.exitCode !== 2) {
|
|
240
|
+
throw new Error('RuleZ failed to block modifications to rulez.ts safety checker.');
|
|
241
|
+
}
|
|
242
|
+
// Attempt edit of sahoo-gateway.ts
|
|
243
|
+
const blockSahoo = rulez.checkFileEdit('src/orchestrator/sahoo-gateway.ts', 'const bypass = true;');
|
|
244
|
+
if (blockSahoo.allowed || blockSahoo.exitCode !== 2) {
|
|
245
|
+
throw new Error('RuleZ failed to block modifications to sahoo-gateway.ts safety gate.');
|
|
246
|
+
}
|
|
247
|
+
// Attempt edit of run-tests.ts
|
|
248
|
+
const blockTests = rulez.checkFileEdit('src/tests/run-tests.ts', 'const pass = true;');
|
|
249
|
+
if (blockTests.allowed || blockTests.exitCode !== 2) {
|
|
250
|
+
throw new Error('RuleZ failed to block modifications to run-tests.ts test suite.');
|
|
251
|
+
}
|
|
252
|
+
// Attempt edit of package.json
|
|
253
|
+
const blockPackage = rulez.checkFileEdit('package.json', '{}');
|
|
254
|
+
if (blockPackage.allowed || blockPackage.exitCode !== 2) {
|
|
255
|
+
throw new Error('RuleZ failed to block modifications to package.json.');
|
|
256
|
+
}
|
|
257
|
+
// Attempt edit of .env
|
|
258
|
+
const blockEnv = rulez.checkFileEdit('.env', 'API_KEY=xxx');
|
|
259
|
+
if (blockEnv.allowed || blockEnv.exitCode !== 2) {
|
|
260
|
+
throw new Error('RuleZ failed to block modifications to .env.');
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
// Dynamic User-Created Tests Loading
|
|
264
|
+
const dynamicTestsDir = path.join(__dirname, 'dynamic');
|
|
265
|
+
if (fs.existsSync(dynamicTestsDir)) {
|
|
266
|
+
const files = fs.readdirSync(dynamicTestsDir).filter(f => f.endsWith('.js'));
|
|
267
|
+
if (files.length > 0) {
|
|
268
|
+
console.log('\n\x1b[35m=== RUNNING DYNAMIC USER-GENERATED TESTS ===\x1b[0m\n');
|
|
269
|
+
for (const file of files) {
|
|
270
|
+
const filePath = path.join(dynamicTestsDir, file);
|
|
271
|
+
await runTest(`Dynamic Test File: ${file}`, async () => {
|
|
272
|
+
const testModule = require(filePath);
|
|
273
|
+
if (typeof testModule === 'function') {
|
|
274
|
+
await testModule();
|
|
275
|
+
}
|
|
276
|
+
else if (testModule && typeof testModule.run === 'function') {
|
|
277
|
+
await testModule.run();
|
|
278
|
+
}
|
|
279
|
+
else if (testModule && typeof testModule.default === 'function') {
|
|
280
|
+
await testModule.default();
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
throw new Error(`Dynamic test file ${file} does not export a default function, run function, or standard module.exports function.`);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
console.log('\x1b[32;1m=== ALL BINARY ASSERTION TESTS PASSED ===\x1b[0m');
|
|
290
|
+
}
|
|
291
|
+
main().catch(err => {
|
|
292
|
+
console.error('Test execution failed:', err);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getFormattedDiff = getFormattedDiff;
|
|
4
|
+
const shell_tools_1 = require("./shell-tools");
|
|
5
|
+
/**
|
|
6
|
+
* Generates and formats a colorized Git diff for a specific file or the entire workspace.
|
|
7
|
+
*/
|
|
8
|
+
async function getFormattedDiff(filePath) {
|
|
9
|
+
const target = filePath ? `"${filePath}"` : '';
|
|
10
|
+
// Use git's native diffing with forced ANSI color codes
|
|
11
|
+
const cmd = `git diff --color=always ${target}`;
|
|
12
|
+
const result = await (0, shell_tools_1.runCommand)(cmd);
|
|
13
|
+
if (result.exitCode !== 0) {
|
|
14
|
+
return `\x1b[31mError generating diff: ${result.stderr || 'unknown error'}\x1b[0m`;
|
|
15
|
+
}
|
|
16
|
+
const output = result.stdout.trim();
|
|
17
|
+
if (!output) {
|
|
18
|
+
return '\x1b[90m(No changes detected)\x1b[0m';
|
|
19
|
+
}
|
|
20
|
+
// Wrap the diff output inside a visual container box
|
|
21
|
+
const border = '\x1b[36m┌────────────────────────────────────────────────────────────┐\x1b[0m';
|
|
22
|
+
const footer = '\x1b[36m└────────────────────────────────────────────────────────────┘\x1b[0m';
|
|
23
|
+
return `${border}\n\x1b[36m│ CODE CHANGES VISUALIZATION │\x1b[0m\n${border}\n${output}\n${footer}`;
|
|
24
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
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.resolveWorkspacePath = resolveWorkspacePath;
|
|
37
|
+
exports.readFile = readFile;
|
|
38
|
+
exports.fileExists = fileExists;
|
|
39
|
+
exports.writeFile = writeFile;
|
|
40
|
+
exports.editFile = editFile;
|
|
41
|
+
exports.listDir = listDir;
|
|
42
|
+
exports.grepSearch = grepSearch;
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
/**
|
|
46
|
+
* Resolves a path relative to the workspace root and ensures it remains inside the workspace.
|
|
47
|
+
*/
|
|
48
|
+
function resolveWorkspacePath(filePath, workspaceRoot = process.cwd()) {
|
|
49
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
50
|
+
? filePath
|
|
51
|
+
: path.resolve(workspaceRoot, filePath);
|
|
52
|
+
// Security check: ensure path does not escape workspace (e.g. using ../..)
|
|
53
|
+
const relative = path.relative(workspaceRoot, absolutePath);
|
|
54
|
+
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
55
|
+
throw new Error(`Access denied: Path '${filePath}' is outside the workspace root.`);
|
|
56
|
+
}
|
|
57
|
+
return absolutePath;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Reads the content of a file.
|
|
61
|
+
*/
|
|
62
|
+
function readFile(filePath, workspaceRoot) {
|
|
63
|
+
const resolved = resolveWorkspacePath(filePath, workspaceRoot);
|
|
64
|
+
if (!fs.existsSync(resolved)) {
|
|
65
|
+
throw new Error(`File not found: ${filePath}`);
|
|
66
|
+
}
|
|
67
|
+
return fs.readFileSync(resolved, 'utf-8');
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Checks if a file exists at the given path.
|
|
71
|
+
*/
|
|
72
|
+
function fileExists(filePath, workspaceRoot) {
|
|
73
|
+
const resolved = resolveWorkspacePath(filePath, workspaceRoot);
|
|
74
|
+
return fs.existsSync(resolved);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Creates or overwrites a file with content.
|
|
78
|
+
*/
|
|
79
|
+
function writeFile(filePath, content, workspaceRoot) {
|
|
80
|
+
const resolved = resolveWorkspacePath(filePath, workspaceRoot);
|
|
81
|
+
const dir = path.dirname(resolved);
|
|
82
|
+
if (!fs.existsSync(dir)) {
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
fs.writeFileSync(resolved, content, 'utf-8');
|
|
86
|
+
}
|
|
87
|
+
function escapeRegExp(str) {
|
|
88
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Replaces a target string with replacement content inside a file.
|
|
92
|
+
* Falls back to fuzzy whitespace-insensitive matching if exact match is not found.
|
|
93
|
+
*/
|
|
94
|
+
function editFile(filePath, targetContent, replacementContent, workspaceRoot) {
|
|
95
|
+
const resolved = resolveWorkspacePath(filePath, workspaceRoot);
|
|
96
|
+
const content = readFile(resolved, workspaceRoot);
|
|
97
|
+
// Detect if file primarily uses CRLF
|
|
98
|
+
const isCrlf = content.includes('\r\n');
|
|
99
|
+
// Normalize both content and target contents to LF (\n)
|
|
100
|
+
const normalizedContent = content.replace(/\r\n/g, '\n');
|
|
101
|
+
const normalizedTarget = targetContent.replace(/\r\n/g, '\n');
|
|
102
|
+
const normalizedReplacement = replacementContent.replace(/\r\n/g, '\n');
|
|
103
|
+
const occurrences = normalizedContent.split(normalizedTarget).length - 1;
|
|
104
|
+
if (occurrences === 1) {
|
|
105
|
+
let newContent = normalizedContent.replace(normalizedTarget, normalizedReplacement);
|
|
106
|
+
if (isCrlf) {
|
|
107
|
+
newContent = newContent.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
|
|
108
|
+
}
|
|
109
|
+
fs.writeFileSync(resolved, newContent, 'utf-8');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
// Exact match failed or is ambiguous. Try fuzzy whitespace regex matching.
|
|
113
|
+
const tokens = targetContent.trim().split(/\s+/);
|
|
114
|
+
if (tokens.length === 0 || tokens.join('') === '') {
|
|
115
|
+
throw new Error(`Target content to edit is empty or whitespace only.`);
|
|
116
|
+
}
|
|
117
|
+
const regexStr = tokens.map(tok => escapeRegExp(tok)).join('\\s+');
|
|
118
|
+
const regex = new RegExp(regexStr, 'g');
|
|
119
|
+
const matches = content.match(regex);
|
|
120
|
+
const matchCount = matches ? matches.length : 0;
|
|
121
|
+
if (matchCount === 0) {
|
|
122
|
+
throw new Error(`Target content to edit was not found in file: ${filePath} (tried exact and fuzzy whitespace matching).`);
|
|
123
|
+
}
|
|
124
|
+
else if (matchCount > 1) {
|
|
125
|
+
throw new Error(`Target content to edit is ambiguous (found ${matchCount} occurrences fuzzy-matching) in file: ${filePath}. Please provide more context.`);
|
|
126
|
+
}
|
|
127
|
+
// Perform the single replace
|
|
128
|
+
const newContent = content.replace(regex, replacementContent);
|
|
129
|
+
fs.writeFileSync(resolved, newContent, 'utf-8');
|
|
130
|
+
}
|
|
131
|
+
function listDir(dirPath = '.', workspaceRoot) {
|
|
132
|
+
const resolved = resolveWorkspacePath(dirPath, workspaceRoot);
|
|
133
|
+
if (!fs.existsSync(resolved)) {
|
|
134
|
+
throw new Error(`Directory not found: ${dirPath}`);
|
|
135
|
+
}
|
|
136
|
+
const stats = fs.statSync(resolved);
|
|
137
|
+
if (!stats.isDirectory()) {
|
|
138
|
+
throw new Error(`Path is not a directory: ${dirPath}`);
|
|
139
|
+
}
|
|
140
|
+
const items = fs.readdirSync(resolved);
|
|
141
|
+
return items.map(name => {
|
|
142
|
+
const itemPath = path.join(resolved, name);
|
|
143
|
+
const itemStats = fs.statSync(itemPath);
|
|
144
|
+
const isDir = itemStats.isDirectory();
|
|
145
|
+
return {
|
|
146
|
+
name,
|
|
147
|
+
isDir,
|
|
148
|
+
sizeBytes: isDir ? undefined : itemStats.size
|
|
149
|
+
};
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function grepSearch(pattern, searchDir = '.', workspaceRoot = process.cwd()) {
|
|
153
|
+
const resolvedDir = resolveWorkspacePath(searchDir, workspaceRoot);
|
|
154
|
+
const results = [];
|
|
155
|
+
const regex = new RegExp(pattern, 'i'); // Case-insensitive match
|
|
156
|
+
function walk(currentDir) {
|
|
157
|
+
const files = fs.readdirSync(currentDir);
|
|
158
|
+
for (const file of files) {
|
|
159
|
+
const fullPath = path.join(currentDir, file);
|
|
160
|
+
// Skip node_modules, .git, dist
|
|
161
|
+
if (file === 'node_modules' || file === '.git' || file === 'dist' || file === '.gemini') {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const stats = fs.statSync(fullPath);
|
|
165
|
+
if (stats.isDirectory()) {
|
|
166
|
+
walk(fullPath);
|
|
167
|
+
}
|
|
168
|
+
else if (stats.isFile()) {
|
|
169
|
+
// Only search text-like files
|
|
170
|
+
const ext = path.extname(file).toLowerCase();
|
|
171
|
+
if (['.ts', '.js', '.json', '.md', '.txt', '.env', '.html', '.css'].includes(ext)) {
|
|
172
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
173
|
+
const lines = content.split('\n');
|
|
174
|
+
lines.forEach((line, index) => {
|
|
175
|
+
if (regex.test(line)) {
|
|
176
|
+
results.push({
|
|
177
|
+
filePath: path.relative(workspaceRoot, fullPath).replace(/\\/g, '/'),
|
|
178
|
+
lineNumber: index + 1,
|
|
179
|
+
lineContent: line.trim()
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (fs.existsSync(resolvedDir)) {
|
|
188
|
+
walk(resolvedDir);
|
|
189
|
+
}
|
|
190
|
+
return results.slice(0, 50); // Cap at 50 results
|
|
191
|
+
}
|