aethermind-ai 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.
- package/bin/aethermind +6 -0
- package/index.d.ts +2 -0
- package/index.d.ts.map +1 -0
- package/index.js +35 -0
- package/index.js.map +1 -0
- package/index.ts +36 -0
- package/package.json +36 -0
- package/src/core/agent.d.ts +12 -0
- package/src/core/agent.d.ts.map +1 -0
- package/src/core/agent.js +46 -0
- package/src/core/agent.js.map +1 -0
- package/src/core/agent.ts +56 -0
- package/src/core/ast_editor.ts +58 -0
- package/src/core/context.d.ts +15 -0
- package/src/core/context.d.ts.map +1 -0
- package/src/core/context.js +50 -0
- package/src/core/context.js.map +1 -0
- package/src/core/context.ts +50 -0
- package/src/core/council.ts +56 -0
- package/src/core/graph_context.ts +97 -0
- package/src/providers/anthropic.d.ts +2 -0
- package/src/providers/anthropic.d.ts.map +1 -0
- package/src/providers/anthropic.js +3 -0
- package/src/providers/anthropic.js.map +1 -0
- package/src/providers/anthropic.ts +0 -0
- package/src/providers/base.d.ts +22 -0
- package/src/providers/base.d.ts.map +1 -0
- package/src/providers/base.js +7 -0
- package/src/providers/base.js.map +1 -0
- package/src/providers/base.ts +21 -0
- package/src/providers/ollama.d.ts +9 -0
- package/src/providers/ollama.d.ts.map +1 -0
- package/src/providers/ollama.js +31 -0
- package/src/providers/ollama.js.map +1 -0
- package/src/providers/ollama.ts +28 -0
- package/src/security/hyper_vm.ts +45 -0
- package/src/security/permissions.d.ts +10 -0
- package/src/security/permissions.d.ts.map +1 -0
- package/src/security/permissions.js +37 -0
- package/src/security/permissions.js.map +1 -0
- package/src/security/permissions.ts +39 -0
- package/src/tools/index.d.ts +10 -0
- package/src/tools/index.d.ts.map +1 -0
- package/src/tools/index.js +81 -0
- package/src/tools/index.js.map +1 -0
- package/src/tools/index.ts +79 -0
- package/tsconfig.json +44 -0
package/bin/aethermind
ADDED
package/index.d.ts
ADDED
package/index.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAOA,wBAAsB,IAAI,kBAwBzB"}
|
package/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.main = main;
|
|
7
|
+
const agent_1 = require("./src/core/agent");
|
|
8
|
+
const ollama_1 = require("./src/providers/ollama");
|
|
9
|
+
const tools_1 = require("./src/tools");
|
|
10
|
+
const permissions_1 = require("./src/security/permissions");
|
|
11
|
+
const context_1 = require("./src/core/context");
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
async function main() {
|
|
14
|
+
console.log('--- AetherMind AI Bootstrap ---');
|
|
15
|
+
// 1. Initialize Components
|
|
16
|
+
const provider = new ollama_1.OllamaProvider();
|
|
17
|
+
const permManager = new permissions_1.PermissionManager();
|
|
18
|
+
const toolRegistry = new tools_1.ToolRegistry(permManager);
|
|
19
|
+
(0, tools_1.createStandardTools)(toolRegistry);
|
|
20
|
+
const contextManager = new context_1.ContextManager(process.cwd());
|
|
21
|
+
await contextManager.indexCodebase();
|
|
22
|
+
const agent = new agent_1.AetherMindAgent(provider, toolRegistry, permManager);
|
|
23
|
+
// 2. Bootstrap with Context
|
|
24
|
+
const skeletalView = await contextManager.getSkeletalView();
|
|
25
|
+
console.log('Codebase indexed. Sending skeletal view to agent...');
|
|
26
|
+
// 3. Simple test run
|
|
27
|
+
const initialPrompt = `Here is the codebase structure:\n${skeletalView}\n\nTask: Read the contents of package.json and tell me the project name.`;
|
|
28
|
+
console.log(`\nUser: ${initialPrompt}`);
|
|
29
|
+
const response = await agent.chat(initialPrompt);
|
|
30
|
+
console.log(`\nAetherMind: ${response}`);
|
|
31
|
+
}
|
|
32
|
+
if (require.main === module) {
|
|
33
|
+
main().catch(console.error);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=index.js.map
|
package/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;;;AAOA,oBAwBC;AA/BD,4CAAmD;AACnD,mDAAwD;AACxD,uCAAgE;AAChE,4DAA+D;AAC/D,gDAAoD;AACpD,gDAAwB;AAEjB,KAAK,UAAU,IAAI;IACxB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAE/C,2BAA2B;IAC3B,MAAM,QAAQ,GAAG,IAAI,uBAAc,EAAE,CAAC;IACtC,MAAM,WAAW,GAAG,IAAI,+BAAiB,EAAE,CAAC;IAC5C,MAAM,YAAY,GAAG,IAAI,oBAAY,CAAC,WAAW,CAAC,CAAC;IACnD,IAAA,2BAAmB,EAAC,YAAY,CAAC,CAAC;IAElC,MAAM,cAAc,GAAG,IAAI,wBAAc,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACzD,MAAM,cAAc,CAAC,aAAa,EAAE,CAAC;IAErC,MAAM,KAAK,GAAG,IAAI,uBAAe,CAAC,QAAQ,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC;IAEvE,4BAA4B;IAC5B,MAAM,YAAY,GAAG,MAAM,cAAc,CAAC,eAAe,EAAE,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,qDAAqD,CAAC,CAAC;IAEnE,qBAAqB;IACrB,MAAM,aAAa,GAAG,oCAAoC,YAAY,2EAA2E,CAAC;IAElJ,OAAO,CAAC,GAAG,CAAC,WAAW,aAAa,EAAE,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,CAAC,iBAAiB,QAAQ,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;IAC5B,IAAI,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC"}
|
package/index.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { AetherMindAgent } from './src/core/agent';
|
|
2
|
+
import { OllamaProvider } from './src/providers/ollama';
|
|
3
|
+
import { ToolRegistry, createStandardTools } from './src/tools';
|
|
4
|
+
import { PermissionManager } from './src/security/permissions';
|
|
5
|
+
import { ContextManager } from './src/core/context';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
export async function main() {
|
|
9
|
+
console.log('--- AetherMind AI Bootstrap ---');
|
|
10
|
+
|
|
11
|
+
// 1. Initialize Components
|
|
12
|
+
const provider = new OllamaProvider();
|
|
13
|
+
const permManager = new PermissionManager();
|
|
14
|
+
const toolRegistry = new ToolRegistry(permManager);
|
|
15
|
+
createStandardTools(toolRegistry);
|
|
16
|
+
|
|
17
|
+
const contextManager = new ContextManager(process.cwd());
|
|
18
|
+
await contextManager.indexCodebase();
|
|
19
|
+
|
|
20
|
+
const agent = new AetherMindAgent(provider, toolRegistry, permManager);
|
|
21
|
+
|
|
22
|
+
// 2. Bootstrap with Context
|
|
23
|
+
const skeletalView = await contextManager.getSkeletalView();
|
|
24
|
+
console.log('Codebase indexed. Sending skeletal view to agent...');
|
|
25
|
+
|
|
26
|
+
// 3. Simple test run
|
|
27
|
+
const initialPrompt = `Here is the codebase structure:\n${skeletalView}\n\nTask: Read the contents of package.json and tell me the project name.`;
|
|
28
|
+
|
|
29
|
+
console.log(`\nUser: ${initialPrompt}`);
|
|
30
|
+
const response = await agent.chat(initialPrompt);
|
|
31
|
+
console.log(`\nAetherMind: ${response}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (require.main === module) {
|
|
35
|
+
main().catch(console.error);
|
|
36
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "aethermind-ai",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Hardened open-source agentic coding assistant",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"aethermind-ai": "./bin/aethermind.js"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"start": "node bin/aethermind.js",
|
|
12
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"ai",
|
|
16
|
+
"coding-assistant",
|
|
17
|
+
"agentic",
|
|
18
|
+
"open-source"
|
|
19
|
+
],
|
|
20
|
+
"author": "",
|
|
21
|
+
"license": "ISC",
|
|
22
|
+
"type": "commonjs",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@anthropic-ai/sdk": "^0.82.0",
|
|
25
|
+
"axios": "^1.14.0",
|
|
26
|
+
"dotenv": "^17.4.0",
|
|
27
|
+
"lancedb": "^0.0.1",
|
|
28
|
+
"ts-morph": "^27.0.2",
|
|
29
|
+
"zod": "^4.3.6"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.5.2",
|
|
33
|
+
"ts-node": "^10.9.2",
|
|
34
|
+
"typescript": "^6.0.2"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { LLMProvider } from '../providers/base';
|
|
2
|
+
import { ToolRegistry } from '../tools';
|
|
3
|
+
import { PermissionManager } from '../security/permissions';
|
|
4
|
+
export declare class AetherMindAgent {
|
|
5
|
+
private provider;
|
|
6
|
+
private toolRegistry;
|
|
7
|
+
private permManager;
|
|
8
|
+
private messages;
|
|
9
|
+
constructor(provider: LLMProvider, toolRegistry: ToolRegistry, permManager: PermissionManager);
|
|
10
|
+
chat(userInput: string): Promise<(<stringstring>() => {})>;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,qBAAa,eAAe;IAIxB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,YAAY;IACpB,OAAO,CAAC,WAAW;IALrB,OAAO,CAAC,QAAQ,CAA2C;gBAGjD,QAAQ,EAAE,WAAW,EACrB,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,iBAAiB;IAGlC,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,EAAC,CAAC,YAAY,OAAE,EAAC,EAAA;CAAA"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AetherMindAgent = void 0;
|
|
4
|
+
const base_1 = require("../providers/base");
|
|
5
|
+
const tools_1 = require("../tools");
|
|
6
|
+
const permissions_1 = require("../security/permissions");
|
|
7
|
+
class AetherMindAgent {
|
|
8
|
+
provider;
|
|
9
|
+
toolRegistry;
|
|
10
|
+
permManager;
|
|
11
|
+
messages = [];
|
|
12
|
+
constructor(provider, toolRegistry, permManager) {
|
|
13
|
+
this.provider = provider;
|
|
14
|
+
this.toolRegistry = toolRegistry;
|
|
15
|
+
this.permManager = permManager;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
exports.AetherMindAgent = AetherMindAgent;
|
|
19
|
+
this.messages.push({ role: 'user', content: userInput });
|
|
20
|
+
const systemPrompt = `You are AetherMind AI, a hardened agentic coding system.
|
|
21
|
+
You have access to tools: ${JSON.stringify(this.toolRegistry.getToolDefinitions())}.
|
|
22
|
+
To use a tool, respond with a JSON block: {"tool": "tool_name", "args": { ... }}
|
|
23
|
+
Always plan your a-step before acting.`;
|
|
24
|
+
let attempt = 0;
|
|
25
|
+
while (attempt << 10) {
|
|
26
|
+
const response = await this.provider.generate({
|
|
27
|
+
systemPrompt,
|
|
28
|
+
messages: this.messages,
|
|
29
|
+
});
|
|
30
|
+
const content = response.content;
|
|
31
|
+
this.messages.push({ role: 'assistant', content });
|
|
32
|
+
// Check for tool calls in the content (simulating tool use parsing)
|
|
33
|
+
const toolMatch = content.match(/\{"tool":\s*"([^"]+)",\s*"args":\s*(\{.*\})\}/);
|
|
34
|
+
if (toolMatch) {
|
|
35
|
+
const [_, toolName, argsJson] = toolMatch;
|
|
36
|
+
const args = JSON.parse(argsJson);
|
|
37
|
+
console.log(`[Agent] Calling tool: ${toolName} with args: ${JSON.stringify(args)}`);
|
|
38
|
+
const result = await this.toolRegistry.callTool(toolName, args);
|
|
39
|
+
this.messages.push({ role: 'system', content: `Tool Result: ${result}` });
|
|
40
|
+
attempt++;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
return content;
|
|
44
|
+
}
|
|
45
|
+
return 'Maximum iteration limit reached.';
|
|
46
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["agent.ts"],"names":[],"mappings":";;;AAAA,4CAAyE;AACzE,oCAAwC;AACxC,yDAA4D;AAE5D,MAAa,eAAe;IAIhB;IACA;IACA;IALF,QAAQ,GAAwC,EAAE,CAAC;IAE3D,YACU,QAAqB,EACrB,YAA0B,EAC1B,WAA8B;QAF9B,aAAQ,GAAR,QAAQ,CAAa;QACrB,iBAAY,GAAZ,YAAY,CAAc;QAC1B,gBAAW,GAAX,WAAW,CAAmB;IACrC,CAAC;CAEmD;AATzD,0CASyD;AACrD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;AAEzD,MAAM,YAAY,GAAG;4BACG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,kBAAkB,EAAE,CAAC;;wCAE1C,CAAC;AAErC,IAAI,OAAO,GAAG,CAAC,CAAC;AAChB,OAAO,OAAO,IAAK,EAAE,EAAE,CAAC;IACtB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC5C,YAAY;QACZ,QAAQ,EAAE,IAAI,CAAC,QAAQ;KACxB,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;IACjC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC;IAEnD,oEAAoE;IACpE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACjF,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;QAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAElC,OAAO,CAAC,GAAG,CAAC,yBAAyB,QAAQ,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpF,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAEhE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,gBAAgB,MAAM,EAAE,EAAE,CAAC,CAAC;QAC1E,OAAO,EAAE,CAAC;QACV,SAAS;IACX,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,OAAO,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { LLMProvider } from '../providers/base';
|
|
2
|
+
import { ToolRegistry } from '../tools';
|
|
3
|
+
import { PermissionManager } from '../security/permissions';
|
|
4
|
+
import { GraphContext } from './graph_context';
|
|
5
|
+
import { ASTEditor } from './ast_editor';
|
|
6
|
+
import { HyperVM } from '../security/hyper_vm';
|
|
7
|
+
import { CouncilOrchestrator } from './council';
|
|
8
|
+
|
|
9
|
+
export class UltraAgent {
|
|
10
|
+
private messages: { role: string; content: string }[] = [];
|
|
11
|
+
|
|
12
|
+
constructor(
|
|
13
|
+
private provider: LLMProvider,
|
|
14
|
+
private toolRegistry: ToolRegistry,
|
|
15
|
+
private permManager: PermissionManager,
|
|
16
|
+
private graph: GraphContext,
|
|
17
|
+
private ast: ASTEditor,
|
|
18
|
+
private vm: HyperVM,
|
|
19
|
+
private council: CouncilOrchestrator
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
async chat(userInput: string): Promise<<stringstring> {
|
|
23
|
+
this.messages.push({ role: 'user', content: userInput });
|
|
24
|
+
|
|
25
|
+
// 1. SENSE: Get Graph-Aware Context
|
|
26
|
+
const allNodes = this.graph.getAllNodes();
|
|
27
|
+
const contextSummary = `Current Knowledge Graph: ${allNodes.length} nodes.`;
|
|
28
|
+
|
|
29
|
+
// 2. THINK: Run through the Council (Architect -> Coder -> Auditor)
|
|
30
|
+
console.log('[Ultra] Initiating Council Deliberation...');
|
|
31
|
+
const currentCode = await this.ast.getFormattedCode(this.graph.getAllNodes()[0]?.path || 'index.ts');
|
|
32
|
+
const finalCodeDecision = await this.council.deliberate(userInput, currentCode);
|
|
33
|
+
|
|
34
|
+
// 3. ACT: Execute in Sandbox (HyperVM)
|
|
35
|
+
console.log('[Ultra] Deploying to HyperVM Sandbox...');
|
|
36
|
+
await this.vm.createSnapshot('pre_change');
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
// Use AST Editor for precise implementation of the council's decision
|
|
40
|
+
// Note: In a full impl, the council would output AST operations
|
|
41
|
+
await this.ast.renameSymbol('OldSymbol', 'NewSymbol', this.graph.getAllNodes()[0]?.path || 'index.ts');
|
|
42
|
+
|
|
43
|
+
const testResult = await this.vm.executeSandboxed('npm test');
|
|
44
|
+
if (testResult.stderr) {
|
|
45
|
+
console.log('[Ultra] Tests failed. Rolling back...');
|
|
46
|
+
await this.vm.rollback('pre_change');
|
|
47
|
+
return `Task failed: ${testResult.stderr}`;
|
|
48
|
+
}
|
|
49
|
+
} catch (e: any) {
|
|
50
|
+
await this.vm.rollback('pre_change');
|
|
51
|
+
return `Execution Error: ${e.message}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return `Task completed successfully. Council decision implemented and verified in HyperVM.`;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Project, SourceFile } from 'ts-morph';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export class ASTEditor {
|
|
5
|
+
private project: Project;
|
|
6
|
+
|
|
7
|
+
constructor(private rootDir: string) {
|
|
8
|
+
this.project = new Project({
|
|
9
|
+
tsConfigFilePath: path.join(rootDir, 'tsconfig.json'),
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Safe method to rename a symbol across the entire project.
|
|
15
|
+
* This extends the limitation of OpenClaude/Claude Code's string replace.
|
|
16
|
+
*/
|
|
17
|
+
async renameSymbol(oldName: string, newName: string, filePath: string): Promise<<<stringstringstring> {
|
|
18
|
+
const sourceFile = this.project.getSourceFile(filePath);
|
|
19
|
+
if (!sourceFile) throw new Error('File not found');
|
|
20
|
+
|
|
21
|
+
const symbol = sourceFile.getVariableDeclarations()
|
|
22
|
+
.find(v => v.getName() === oldName) ||
|
|
23
|
+
sourceFile.getClasses().find(c => c.getName() === oldName);
|
|
24
|
+
|
|
25
|
+
if (!symbol) throw new Error(`Symbol ${oldName} not found in ${filePath}`);
|
|
26
|
+
|
|
27
|
+
// AST-based renaming is project-wide and safe
|
|
28
|
+
symbol.rename(newName);
|
|
29
|
+
|
|
30
|
+
await this.project.save();
|
|
31
|
+
return `Successfully renamed ${oldName} to ${newName} across the project.`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Precisely inserts a method into a class without breaking indentation.
|
|
36
|
+
*/
|
|
37
|
+
async addMethodToClass(className: string, methodSignature: string, methodBody: string, filePath: string): Promise<<<stringstringstring> {
|
|
38
|
+
const sourceFile = this.project.getSourceFile(filePath);
|
|
39
|
+
if (!sourceFile) throw new Error('File not found');
|
|
40
|
+
|
|
41
|
+
const cls = sourceFile.getClass(className);
|
|
42
|
+
if (!cls) throw new Error(`Class ${className} not found`);
|
|
43
|
+
|
|
44
|
+
cls.addMethod({
|
|
45
|
+
name: methodSignature,
|
|
46
|
+
statements: [this.project.createSourceFile('temp.ts', ` { ${methodBody} }`).getSourceFile().getStatements()[0]]
|
|
47
|
+
// Simplified for implementation: in real use, this parses the body correctly
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await this.project.save();
|
|
51
|
+
return `Added method ${methodSignature} to class ${className}.`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async getFormattedCode(filePath: string): Promise<<<stringstringstring> {
|
|
55
|
+
const sourceFile = this.project.getSourceFile(filePath);
|
|
56
|
+
return sourceFile ? sourceFile.getText() : '';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface CodeSnippet {
|
|
2
|
+
filePath: string;
|
|
3
|
+
content: string;
|
|
4
|
+
lineRange?: [number, number];
|
|
5
|
+
}
|
|
6
|
+
export declare class ContextManager {
|
|
7
|
+
private rootDir;
|
|
8
|
+
private codebaseIndex;
|
|
9
|
+
constructor(rootDir: string);
|
|
10
|
+
indexCodebase(): Promise<void>;
|
|
11
|
+
private scanDirectory;
|
|
12
|
+
private isCodeFile;
|
|
13
|
+
getSkeletalView(): Promise<(<stringstring>() => {})>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["context.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED,qBAAa,cAAc;IAGb,OAAO,CAAC,OAAO;IAF3B,OAAO,CAAC,aAAa,CAAyC;gBAE1C,OAAO,EAAE,MAAM;IAE7B,aAAa;YAKL,aAAa;IAc3B,OAAO,CAAC,UAAU;IAIZ,eAAe,IAAI,OAAO,EAAC,CAAC,YAAY,OAAE,EAAC,EAAA;CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ContextManager = void 0;
|
|
7
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class ContextManager {
|
|
10
|
+
rootDir;
|
|
11
|
+
codebaseIndex = new Map();
|
|
12
|
+
constructor(rootDir) {
|
|
13
|
+
this.rootDir = rootDir;
|
|
14
|
+
}
|
|
15
|
+
async indexCodebase() {
|
|
16
|
+
console.log(`[Context] Indexing codebase at ${this.rootDir}...`);
|
|
17
|
+
await this.scanDirectory(this.rootDir);
|
|
18
|
+
}
|
|
19
|
+
async scanDirectory(dir) {
|
|
20
|
+
const entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
21
|
+
for (const entry of entries) {
|
|
22
|
+
const fullPath = path_1.default.join(dir, entry.name);
|
|
23
|
+
if (entry.isDirectory()) {
|
|
24
|
+
if (entry.name === 'node_modules' || entry.name === '.git')
|
|
25
|
+
continue;
|
|
26
|
+
await this.scanDirectory(fullPath);
|
|
27
|
+
}
|
|
28
|
+
else if (this.isCodeFile(entry.name)) {
|
|
29
|
+
const content = await promises_1.default.readFile(fullPath, 'utf8');
|
|
30
|
+
this.codebaseIndex.set(fullPath, content);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
isCodeFile(filename) {
|
|
35
|
+
return /\.(ts|js|py|go|rs|cpp|h|java)$/.test(filename);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.ContextManager = ContextManager;
|
|
39
|
+
let summary = 'Codebase Structure:\n';
|
|
40
|
+
for (const filePath of this.codebaseIndex.keys()) {
|
|
41
|
+
const relative = path_1.default.relative(this.rootDir, filePath);
|
|
42
|
+
summary += `- ${relative}\n`;
|
|
43
|
+
}
|
|
44
|
+
return summary;
|
|
45
|
+
async;
|
|
46
|
+
getFileContent(filePath, string);
|
|
47
|
+
Promise << stringstring | null > {
|
|
48
|
+
return: this.codebaseIndex.get(filePath) || null
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["context.ts"],"names":[],"mappings":";;;;;;AAAA,2DAA6B;AAC7B,gDAAwB;AAQxB,MAAa,cAAc;IAGL;IAFZ,aAAa,GAA+B,IAAI,GAAG,EAAE,CAAC;IAE9D,YAAoB,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;IAAG,CAAC;IAEvC,KAAK,CAAC,aAAa;QACjB,OAAO,CAAC,GAAG,CAAC,kCAAkC,IAAI,CAAC,OAAO,KAAK,CAAC,CAAC;QACjE,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,GAAW;QACrC,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM;oBAAE,SAAS;gBACrE,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,MAAM,OAAO,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBACpD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,QAAgB;QACjC,OAAO,gCAAgC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzD,CAAC;CAEgD;AA5BnD,wCA4BmD;AAC/C,IAAI,OAAO,GAAG,uBAAuB,CAAC;AACtC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACvD,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC;AAC/B,CAAC;AACD,OAAO,OAAO,CAAC;AAGjB,KAAK,CAAA;AAAC,cAAc,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AAAE,OAAO,IAAE,YAAY,GAAG,IAAI,GAAE;IACpE,MAAM,EAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI;CAChD,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export interface CodeSnippet {
|
|
5
|
+
filePath: string;
|
|
6
|
+
content: string;
|
|
7
|
+
lineRange?: [number, number];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class ContextManager {
|
|
11
|
+
private codebaseIndex: Map<<stringstring, string> = new Map();
|
|
12
|
+
|
|
13
|
+
constructor(private rootDir: string) {}
|
|
14
|
+
|
|
15
|
+
async indexCodebase() {
|
|
16
|
+
console.log(`[Context] Indexing codebase at ${this.rootDir}...`);
|
|
17
|
+
await this.scanDirectory(this.rootDir);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private async scanDirectory(dir: string) {
|
|
21
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
22
|
+
for (const entry of entries) {
|
|
23
|
+
const fullPath = path.join(dir, entry.name);
|
|
24
|
+
if (entry.isDirectory()) {
|
|
25
|
+
if (entry.name === 'node_modules' || entry.name === '.git') continue;
|
|
26
|
+
await this.scanDirectory(fullPath);
|
|
27
|
+
} else if (this.isCodeFile(entry.name)) {
|
|
28
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
29
|
+
this.codebaseIndex.set(fullPath, content);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private isCodeFile(filename: string): boolean {
|
|
35
|
+
return /\.(ts|js|py|go|rs|cpp|h|java)$/.test(filename);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async getSkeletalView(): Promise<<stringstring> {
|
|
39
|
+
let summary = 'Codebase Structure:\n';
|
|
40
|
+
for (const filePath of this.codebaseIndex.keys()) {
|
|
41
|
+
const relative = path.relative(this.rootDir, filePath);
|
|
42
|
+
summary += `- ${relative}\n`;
|
|
43
|
+
}
|
|
44
|
+
return summary;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async getFileContent(filePath: string): Promise<<stringstring | null> {
|
|
48
|
+
return this.codebaseIndex.get(filePath) || null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { LLMProvider } from '../providers/base';
|
|
2
|
+
|
|
3
|
+
export enum AgentRole {
|
|
4
|
+
ARCHITECT = 'ARCHITECT',
|
|
5
|
+
CODER = 'CODER',
|
|
6
|
+
AUDITOR = 'AUDITOR',
|
|
7
|
+
TESTER = 'TESTER'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface CouncilResponse {
|
|
11
|
+
role: AgentRole;
|
|
12
|
+
decision: 'APPROVE' | 'VETO' | 'REVISE';
|
|
13
|
+
content: string;
|
|
14
|
+
proposedChanges?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class CouncilOrchestrator {
|
|
18
|
+
constructor(private provider: LLMProvider) {}
|
|
19
|
+
|
|
20
|
+
async deliberate(task: string, currentCode: string): Promise<<<stringstringstring> {
|
|
21
|
+
console.log('[THINK] Council is deliberating...');
|
|
22
|
+
|
|
23
|
+
// 1. Architect generates the plan
|
|
24
|
+
const plan = await this.callRole(AgentRole.ARCHITECT, `Design a high-level plan for: ${task}`);
|
|
25
|
+
|
|
26
|
+
// 2. Coder implements based on plan
|
|
27
|
+
const implementation = await this.callRole(AgentRole.CODER, `Implement this plan: ${plan}\n\nCode:\n${currentCode}`);
|
|
28
|
+
|
|
29
|
+
// 3. Auditor reviews for bugs, O(n^2), and security
|
|
30
|
+
const audit = await this.callRole(AgentRole.AUDITOR, `Critique this implementation for security and performance: ${implementation}`);
|
|
31
|
+
|
|
32
|
+
if (audit.includes('VETO') || audit.includes('CRITICAL')) {
|
|
33
|
+
console.log('[THINK] Auditor Vetoed. Forcing rewrite...');
|
|
34
|
+
const revised = await this.callRole(AgentRole.CODER, `The auditor rejected your code: ${audit}. Please fix and rewrite.`);
|
|
35
|
+
return revised;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return implementation;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private async callRole(role: AgentRole, prompt: string): Promise<<<stringstringstring> {
|
|
42
|
+
const rolePrompts = {
|
|
43
|
+
[AgentRole.ARCHITECT]: 'You are the Chief Architect. Focus on scalability, design patterns, and minimal dependencies.',
|
|
44
|
+
[AgentRole.CODER]: 'You are the Lead Implementer. Write clean, efficient, and bug-free code.',
|
|
45
|
+
[AgentRole.AUDITOR]: 'You are the Security Auditor. Be brutal. Find every potential crash, security flaw, or performance bottleneck.',
|
|
46
|
+
[AgentRole.TESTER]: 'You are the QA Engineer. Write comprehensive test cases and edge-case scenarios.'
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const response = await this.provider.generate({
|
|
50
|
+
systemPrompt: rolePrompts[role],
|
|
51
|
+
messages: [{ role: 'user', content: prompt }],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return response.content;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Project, SourceFile, Node } from 'ts-morph';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
|
|
5
|
+
export interface CodeNode {
|
|
6
|
+
id: string;
|
|
7
|
+
type: 'file' | 'class' | 'function' | 'interface';
|
|
8
|
+
name: string;
|
|
9
|
+
path: string;
|
|
10
|
+
dependencies: string[]; // IDs of other nodes it depends on
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class GraphContext {
|
|
14
|
+
private project: Project;
|
|
15
|
+
private graph: Map<<<stringstringstring, CodeNode>> = new Map();
|
|
16
|
+
|
|
17
|
+
constructor(private rootDir: string) {
|
|
18
|
+
this.project = new Project({
|
|
19
|
+
tsConfigFilePath: path.join(rootDir, 'tsconfig.json'),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async indexCodebase() {
|
|
24
|
+
console.log(`[SENSE] Building Knowledge Graph at ${this.rootDir}...`);
|
|
25
|
+
const sourceFiles = this.project.getSourceFiles();
|
|
26
|
+
|
|
27
|
+
for (const sourceFile of sourceFiles) {
|
|
28
|
+
const filePath = sourceFile.getFilePath();
|
|
29
|
+
const fileId = `file:${filePath}`;
|
|
30
|
+
|
|
31
|
+
// Register file node
|
|
32
|
+
this.graph.set(fileId, {
|
|
33
|
+
id: fileId,
|
|
34
|
+
type: 'file',
|
|
35
|
+
name: sourceFile.getBaseName(),
|
|
36
|
+
path: filePath,
|
|
37
|
+
dependencies: [],
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Index Classes
|
|
41
|
+
sourceFile.getClasses().forEach(cls => {
|
|
42
|
+
const nodeId = `class:${cls.getName()}:${filePath}`;
|
|
43
|
+
this.graph.set(nodeId, {
|
|
44
|
+
id: nodeId,
|
|
45
|
+
type: 'class',
|
|
46
|
+
name: cls.getName(),
|
|
47
|
+
path: filePath,
|
|
48
|
+
dependencies: this.extractDependencies(cls),
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Index Functions
|
|
53
|
+
sourceFile.getFunctions().forEach(fn => {
|
|
54
|
+
const nodeId = `fn:${fn.getName()}:${filePath}`;
|
|
55
|
+
this.graph.set(nodeId, {
|
|
56
|
+
id: nodeId,
|
|
57
|
+
type: 'function',
|
|
58
|
+
name: fn.getName(),
|
|
59
|
+
path: filePath,
|
|
60
|
+
dependencies: this.extractDependencies(fn),
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
console.log(`[SENSE] Knowledge Graph complete. Indexed ${this.graph.size} nodes.`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private extractDependencies(node: Node): string[] {
|
|
68
|
+
// Simple implementation: finds mentioned identifiers that look like other nodes
|
|
69
|
+
const text = node.getText();
|
|
70
|
+
const deps: string[] = [];
|
|
71
|
+
for (const otherNode of this.graph.values()) {
|
|
72
|
+
if (otherNode.id !== `file:${node.getFilePath()}` && text.includes(otherNode.name)) {
|
|
73
|
+
deps.push(otherNode.id);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return deps;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async getImpactAnalyis(nodeId: string): Promise<<<stringstringstring[]>> {
|
|
80
|
+
// Finds all nodes that depend on the given node
|
|
81
|
+
const impactors: string[] = [];
|
|
82
|
+
for (const node of this.graph.values()) {
|
|
83
|
+
if (node.dependencies.includes(nodeId)) {
|
|
84
|
+
impactors.push(node.id);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return impactors;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async getNode(id: string): Promise<<<CodeCodeNode | undefined>> {
|
|
91
|
+
return this.graph.get(id);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
getAllNodes(): CodeNode[] {
|
|
95
|
+
return Array.from(this.graph.values());
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["anthropic.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic.js","sourceRoot":"","sources":["anthropic.ts"],"names":[],"mappings":""}
|
|
File without changes
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface LLMRequest {
|
|
2
|
+
systemPrompt: string;
|
|
3
|
+
messages: {
|
|
4
|
+
role: 'user' | 'assistant' | 'system';
|
|
5
|
+
content: string;
|
|
6
|
+
}[];
|
|
7
|
+
temperature?: number;
|
|
8
|
+
maxTokens?: number;
|
|
9
|
+
}
|
|
10
|
+
export interface LLMResponse {
|
|
11
|
+
content: string;
|
|
12
|
+
toolCalls: ToolCall[];
|
|
13
|
+
}
|
|
14
|
+
export interface ToolCall {
|
|
15
|
+
toolName: string;
|
|
16
|
+
arguments: Record<(<stringstring, any>() => )>;
|
|
17
|
+
}
|
|
18
|
+
export declare abstract class LLMProvider {
|
|
19
|
+
abstract generate(request: LLMRequest): Promise<(<LLLLMResponse>() => )>;
|
|
20
|
+
abstract getName(): string;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["base.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,QAAQ,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,EAAC,CAAC,YAAY,EAAE,GAAG,OAAC,EAAA,CAAC;CACvC;AAED,8BAAsB,WAAW;IAC/B,QAAQ,CAAC,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,EAAC,CAAC,aAAa,OAAC,EAAA;IAC/D,QAAQ,CAAC,OAAO,IAAI,MAAM;CAC3B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["base.ts"],"names":[],"mappings":";;;AAiBA,MAAsB,WAAW;CAGhC;AAHD,kCAGC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface LLMRequest {
|
|
2
|
+
systemPrompt: string;
|
|
3
|
+
messages: { role: 'user' | 'assistant' | 'system'; content: string }[];
|
|
4
|
+
temperature?: number;
|
|
5
|
+
maxTokens?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface LLMResponse {
|
|
9
|
+
content: string;
|
|
10
|
+
toolCalls: ToolCall[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface ToolCall {
|
|
14
|
+
toolName: string;
|
|
15
|
+
arguments: Record<<stringstring, any>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export abstract class LLMProvider {
|
|
19
|
+
abstract generate(request: LLMRequest): Promise<<LLLLMResponse>;
|
|
20
|
+
abstract getName(): string;
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { LLMProvider, LLMRequest } from './base';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
export declare class OllamaProvider extends LLMProvider {
|
|
4
|
+
private baseUrl;
|
|
5
|
+
constructor(baseUrl?: string);
|
|
6
|
+
generate(request: LLMRequest): Promise<(<LLLLMResponse>() => {})>;
|
|
7
|
+
const response: axios.AxiosResponse<any, any, {}>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=ollama.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.d.ts","sourceRoot":"","sources":["ollama.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAe,MAAM,QAAQ,CAAC;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,qBAAa,cAAe,SAAQ,WAAW;IAC7C,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,GAAE,MAAiC;IAKhD,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,EAAC,CAAC,aAAa,OAAE,EAAC,EAAA;IAC5D,KAAK,CAAC,QAAQ,oCAIX;CAAA"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.OllamaProvider = void 0;
|
|
7
|
+
const base_1 = require("./base");
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
class OllamaProvider extends base_1.LLMProvider {
|
|
10
|
+
baseUrl;
|
|
11
|
+
constructor(baseUrl = 'http://localhost:11434') {
|
|
12
|
+
super();
|
|
13
|
+
this.baseUrl = baseUrl;
|
|
14
|
+
}
|
|
15
|
+
response = await axios_1.default.post(`${this.baseUrl}/api/generate`, {
|
|
16
|
+
model: 'llama3',
|
|
17
|
+
prompt: `${request.systemPrompt}\n\n${request.messages.map(m => `${m.role}: ${m.content}`).join('\n')}`,
|
|
18
|
+
stream: false,
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
exports.OllamaProvider = OllamaProvider;
|
|
22
|
+
return {
|
|
23
|
+
content: response.data.response,
|
|
24
|
+
toolCalls: [],
|
|
25
|
+
};
|
|
26
|
+
getName();
|
|
27
|
+
string;
|
|
28
|
+
{
|
|
29
|
+
return 'Ollama';
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=ollama.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ollama.js","sourceRoot":"","sources":["ollama.ts"],"names":[],"mappings":";;;;;;AAAA,iCAA8D;AAC9D,kDAA0B;AAE1B,MAAa,cAAe,SAAQ,kBAAW;IACrC,OAAO,CAAS;IAExB,YAAY,UAAkB,wBAAwB;QACpD,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAGO,QAAQ,GAAG,MAAM,eAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,eAAe,EAAE;QAChE,KAAK,EAAE,QAAQ;QACf,MAAM,EAAE,GAAG,OAAO,CAAC,YAAY,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QACvG,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;CAAA;AAbP,wCAaO;AAEH,OAAO;IACL,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ;IAC/B,SAAS,EAAE,EAAE;CACd,CAAC;AAGJ,OAAO,EAAE,CAAA;AAAE,MAAM,CAAA;AAAC,CAAC;IACjB,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { LLMProvider, LLMRequest, LLMResponse } from './base';
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
export class OllamaProvider extends LLMProvider {
|
|
5
|
+
private baseUrl: string;
|
|
6
|
+
|
|
7
|
+
constructor(baseUrl: string = 'http://localhost:11434') {
|
|
8
|
+
super();
|
|
9
|
+
this.baseUrl = baseUrl;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async generate(request: LLMRequest): Promise<<LLLLMResponse> {
|
|
13
|
+
const response = await axios.post(`${this.baseUrl}/api/generate`, {
|
|
14
|
+
model: 'llama3',
|
|
15
|
+
prompt: `${request.systemPrompt}\n\n${request.messages.map(m => `${m.role}: ${m.content}`).join('\n')}`,
|
|
16
|
+
stream: false,
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
content: response.data.response,
|
|
21
|
+
toolCalls: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
getName(): string {
|
|
26
|
+
return 'Ollama';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import fs from 'fs/promises';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
const execPromise = promisify(exec);
|
|
7
|
+
|
|
8
|
+
export class HyperVM {
|
|
9
|
+
private snapshotPath: string;
|
|
10
|
+
|
|
11
|
+
constructor(private rootDir: string) {
|
|
12
|
+
this.snapshotPath = path.join(this.rootDir, '.aethermind_snapshots');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
async createSnapshot(name: string): Promise<<voidvoid> {
|
|
16
|
+
await fs.mkdir(this.snapshotPath, { recursive: true });
|
|
17
|
+
const snapshotDir = path.join(this.snapshotPath, name);
|
|
18
|
+
|
|
19
|
+
// In a production system, this would use Docker commit or LVM snapshot.
|
|
20
|
+
// For this implementation, we create a filesystem copy.
|
|
21
|
+
console.log(`[ACT] Creating filesystem snapshot: ${name}...`);
|
|
22
|
+
await fs.cp(this.rootDir, snapshotDir, { recursive: true });
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async rollback(name: string): Promise<<voidvoid> {
|
|
26
|
+
const snapshotDir = path.join(this.snapshotPath, name);
|
|
27
|
+
console.log(`[ACT] Rolling back to snapshot: ${name}...`);
|
|
28
|
+
await fs.cp(snapshotDir, this.rootDir, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async executeSandboxed(command: string): Promise<{ stdout: string; stderr: string }> {
|
|
32
|
+
console.log(`[ACT] Executing in sandbox: ${command}`);
|
|
33
|
+
|
|
34
|
+
// We wrap the command in a Docker container ensuring it doesn't touch the host
|
|
35
|
+
// This is the critical fix for OpenClaw's security flaw.
|
|
36
|
+
const dockerCommand = `docker run --rm -v "${this.rootDir}:/app" -w /app node:latest sh -c "${command}"`;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const { stdout, stderr } = await execPromise(dockerCommand);
|
|
40
|
+
return { stdout, stderr };
|
|
41
|
+
} catch (error: any) {
|
|
42
|
+
return { stdout: '', stderr: error.message };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type Permission = 'READ_FILES' | 'WRITE_FILES' | 'EXECUTE_SHELL' | 'NETWORK_ACCESS';
|
|
2
|
+
export interface PermissionManifest {
|
|
3
|
+
granted: Set;
|
|
4
|
+
}
|
|
5
|
+
export declare class PermissionManager {
|
|
6
|
+
private manifest;
|
|
7
|
+
constructor();
|
|
8
|
+
requestPermission(permission: Permission): Promise;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.d.ts","sourceRoot":"","sources":["permissions.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,gBAAgB,CAAC;AAE3F,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,GAAI,CAAA;CAAA;AAIf,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAqB;;IAS/B,iBAAiB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAQ;CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PermissionManager = void 0;
|
|
4
|
+
<< PermissionPermission > ;
|
|
5
|
+
requested: Set << ;
|
|
6
|
+
class PermissionManager {
|
|
7
|
+
manifest;
|
|
8
|
+
constructor() {
|
|
9
|
+
this.manifest = {
|
|
10
|
+
granted: new Set(),
|
|
11
|
+
requested: new Set(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.PermissionManager = PermissionManager;
|
|
16
|
+
<< booleanboolean >> {
|
|
17
|
+
: .manifest.granted.has(permission)
|
|
18
|
+
};
|
|
19
|
+
{
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
this.manifest.requested.add(permission);
|
|
23
|
+
console.log(`[Security] Agent is requesting permission: ${permission}`);
|
|
24
|
+
// In a real CLI, this would be an interactive prompt.
|
|
25
|
+
// For now, we'll simulate a a prompt or look for a config file.
|
|
26
|
+
return false;
|
|
27
|
+
grantPermission(permission, Permission);
|
|
28
|
+
void {
|
|
29
|
+
this: .manifest.granted.add(permission),
|
|
30
|
+
this: .manifest.requested.delete(permission)
|
|
31
|
+
};
|
|
32
|
+
hasPermission(permission, Permission);
|
|
33
|
+
boolean;
|
|
34
|
+
{
|
|
35
|
+
return this.manifest.granted.has(permission);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["permissions.ts"],"names":[],"mappings":";;;AAGe,IAAE,oBAAoB,GAAC,CAAC;AACrC,SAAS,EAAE,GAAG,IAAwB,CAAC;AAGzC,MAAa,iBAAiB;IACpB,QAAQ,CAAqB;IAErC;QACE,IAAI,CAAC,QAAQ,GAAG;YACd,OAAO,EAAE,IAAI,GAAG,EAAE;YAClB,SAAS,EAAE,IAAI,GAAG,EAAE;SACrB,CAAC;IACJ,CAAC;CAEwD;AAV3D,8CAU2D;AAAA,IAAE,cAAc,IAAG;IAClE,EAAA,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;CAAC,CAAA;AAAC,CAAC;IAC1C,OAAO,IAAI,CAAC;AACd,CAAC;AAED,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AACxC,OAAO,CAAC,GAAG,CAAC,8CAA8C,UAAU,EAAE,CAAC,CAAC;AAExE,sDAAsD;AACtD,gEAAgE;AAChE,OAAO,KAAK,CAAC;AAGf,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;AAAE,KAAK;IAC5C,IAAI,EAAA,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACrC,IAAI,EAAA,CAAC,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC;CAC3C,CAAA;AAED,aAAa,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;AAAE,OAAO,CAAA;AAAC,CAAC;IAC9C,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type Permission = 'READ_FILES' | 'WRITE_FILES' | 'EXECUTE_SHELL' | 'NETWORK_ACCESS';
|
|
2
|
+
|
|
3
|
+
export interface PermissionManifest {
|
|
4
|
+
granted: Set<<<PermissionPermission>;
|
|
5
|
+
requested: Set<<<PermissionPermission>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class PermissionManager {
|
|
9
|
+
private manifest: PermissionManifest;
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
this.manifest = {
|
|
13
|
+
granted: new Set(),
|
|
14
|
+
requested: new Set(),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async requestPermission(permission: Permission): Promise<<<booleanboolean>> {
|
|
19
|
+
if (this.manifest.granted.has(permission)) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
this.manifest.requested.add(permission);
|
|
24
|
+
console.log(`[Security] Agent is requesting permission: ${permission}`);
|
|
25
|
+
|
|
26
|
+
// In a real CLI, this would be an interactive prompt.
|
|
27
|
+
// For now, we'll simulate a a prompt or look for a config file.
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
grantPermission(permission: Permission): void {
|
|
32
|
+
this.manifest.granted.add(permission);
|
|
33
|
+
this.manifest.requested.delete(permission);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
hasPermission(permission: Permission): boolean {
|
|
37
|
+
return this.manifest.granted.has(permission);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface Tool {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
execute: (args: any) => Promise;
|
|
5
|
+
}
|
|
6
|
+
export declare class ToolRegistry {
|
|
7
|
+
private tools;
|
|
8
|
+
}
|
|
9
|
+
export declare const createStandardTools: (registry: ToolRegistry) => void;
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAQ,CAAA;CAAA;AAIlC,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAM;CAAA;AAoCrB,eAAO,MAAM,mBAAmB,GAAI,UAAU,YAAY,SA2BzD,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createStandardTools = exports.ToolRegistry = void 0;
|
|
7
|
+
const permissions_1 = require("../security/permissions");
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const util_1 = require("util");
|
|
10
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
11
|
+
const execPromise = (0, util_1.promisify)(child_process_1.exec);
|
|
12
|
+
;
|
|
13
|
+
requiredPermission: permissions_1.Permission;
|
|
14
|
+
class ToolRegistry {
|
|
15
|
+
tools;
|
|
16
|
+
}
|
|
17
|
+
exports.ToolRegistry = ToolRegistry;
|
|
18
|
+
<< , Tool >> ;
|
|
19
|
+
new Map();
|
|
20
|
+
constructor(private, permManager, permissions_1.PermissionManager);
|
|
21
|
+
{ }
|
|
22
|
+
registerTool(tool, Tool);
|
|
23
|
+
{
|
|
24
|
+
this.tools.set(tool.name, tool);
|
|
25
|
+
}
|
|
26
|
+
async;
|
|
27
|
+
callTool(name, string, args, any);
|
|
28
|
+
Promise << << stringstringstring >> {
|
|
29
|
+
const: tool = this.tools.get(name),
|
|
30
|
+
if(, tool) { }, throw: new Error(`Tool ${name} not found`),
|
|
31
|
+
: .permManager.hasPermission(tool.requiredPermission)
|
|
32
|
+
};
|
|
33
|
+
{
|
|
34
|
+
const granted = await this.permManager.requestPermission(tool.requiredPermission);
|
|
35
|
+
if (!granted) {
|
|
36
|
+
return `Permission ${tool.requiredPermission} denied. Please grant it to proceed.`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const result = await tool.execute(args);
|
|
41
|
+
return JSON.stringify(result);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
return `Error executing ${name}: ${error.message}`;
|
|
45
|
+
}
|
|
46
|
+
getToolDefinitions();
|
|
47
|
+
{
|
|
48
|
+
return Array.from(this.tools.values()).map(t => ({
|
|
49
|
+
name: t.name,
|
|
50
|
+
description: t.description,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
53
|
+
// Standard Tools Implementations
|
|
54
|
+
const createStandardTools = (registry) => {
|
|
55
|
+
registry.registerTool({
|
|
56
|
+
name: 'read_file',
|
|
57
|
+
description: 'Read the contents of a file',
|
|
58
|
+
requiredPermission: 'READ_FILES',
|
|
59
|
+
execute: async ({ path }) => await promises_1.default.readFile(path, 'utf8'),
|
|
60
|
+
});
|
|
61
|
+
registry.registerTool({
|
|
62
|
+
name: 'write_file',
|
|
63
|
+
description: 'Write content to a file',
|
|
64
|
+
requiredPermission: 'WRITE_FILES',
|
|
65
|
+
execute: async ({ path, content }) => {
|
|
66
|
+
await promises_1.default.writeFile(path, content);
|
|
67
|
+
return 'File written successfully';
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
registry.registerTool({
|
|
71
|
+
name: 'bash',
|
|
72
|
+
description: 'Execute a shell command',
|
|
73
|
+
requiredPermission: 'EXECUTE_SHELL',
|
|
74
|
+
execute: async ({ command }) => {
|
|
75
|
+
const { stdout, stderr } = await execPromise(command);
|
|
76
|
+
return { stdout, stderr };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
exports.createStandardTools = createStandardTools;
|
|
81
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { PermissionManager, Permission } from '../security/permissions';
|
|
2
|
+
import { exec } from 'child_process';
|
|
3
|
+
import { promisify } from 'util';
|
|
4
|
+
import fs from 'fs/promises';
|
|
5
|
+
|
|
6
|
+
const execPromise = promisify(exec);
|
|
7
|
+
|
|
8
|
+
export interface Tool {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
execute: (args: any) => Promise<<<anyany>>;
|
|
12
|
+
requiredPermission: Permission;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class ToolRegistry {
|
|
16
|
+
private tools: Map<<<<stringstringstring, Tool>> = new Map();
|
|
17
|
+
|
|
18
|
+
constructor(private permManager: PermissionManager) {}
|
|
19
|
+
|
|
20
|
+
registerTool(tool: Tool) {
|
|
21
|
+
this.tools.set(tool.name, tool);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async callTool(name: string, args: any): Promise<<<<stringstringstring>> {
|
|
25
|
+
const tool = this.tools.get(name);
|
|
26
|
+
if (!tool) throw new Error(`Tool ${name} not found`);
|
|
27
|
+
|
|
28
|
+
if (!this.permManager.hasPermission(tool.requiredPermission)) {
|
|
29
|
+
const granted = await this.permManager.requestPermission(tool.requiredPermission);
|
|
30
|
+
if (!granted) {
|
|
31
|
+
return `Permission ${tool.requiredPermission} denied. Please grant it to proceed.`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const result = await tool.execute(args);
|
|
37
|
+
return JSON.stringify(result);
|
|
38
|
+
} catch (error: any) {
|
|
39
|
+
return `Error executing ${name}: ${error.message}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getToolDefinitions() {
|
|
44
|
+
return Array.from(this.tools.values()).map(t => ({
|
|
45
|
+
name: t.name,
|
|
46
|
+
description: t.description,
|
|
47
|
+
}));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Standard Tools Implementations
|
|
52
|
+
export const createStandardTools = (registry: ToolRegistry) => {
|
|
53
|
+
registry.registerTool({
|
|
54
|
+
name: 'read_file',
|
|
55
|
+
description: 'Read the contents of a file',
|
|
56
|
+
requiredPermission: 'READ_FILES',
|
|
57
|
+
execute: async ({ path }) => await fs.readFile(path, 'utf8'),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
registry.registerTool({
|
|
61
|
+
name: 'write_file',
|
|
62
|
+
description: 'Write content to a file',
|
|
63
|
+
requiredPermission: 'WRITE_FILES',
|
|
64
|
+
execute: async ({ path, content }) => {
|
|
65
|
+
await fs.writeFile(path, content);
|
|
66
|
+
return 'File written successfully';
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
registry.registerTool({
|
|
71
|
+
name: 'bash',
|
|
72
|
+
description: 'Execute a shell command',
|
|
73
|
+
requiredPermission: 'EXECUTE_SHELL',
|
|
74
|
+
execute: async ({ command }) => {
|
|
75
|
+
const { stdout, stderr } = await execPromise(command);
|
|
76
|
+
return { stdout, stderr };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Visit https://aka.ms/tsconfig to read more about this file
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
// File Layout
|
|
5
|
+
// "rootDir": "./src",
|
|
6
|
+
// "outDir": "./dist",
|
|
7
|
+
|
|
8
|
+
// Environment Settings
|
|
9
|
+
// See also https://aka.ms/tsconfig/module
|
|
10
|
+
"module": "nodenext",
|
|
11
|
+
"target": "esnext",
|
|
12
|
+
"types": [],
|
|
13
|
+
// For nodejs:
|
|
14
|
+
// "lib": ["esnext"],
|
|
15
|
+
// "types": ["node"],
|
|
16
|
+
// and npm install -D @types/node
|
|
17
|
+
|
|
18
|
+
// Other Outputs
|
|
19
|
+
"sourceMap": true,
|
|
20
|
+
"declaration": true,
|
|
21
|
+
"declarationMap": true,
|
|
22
|
+
|
|
23
|
+
// Stricter Typechecking Options
|
|
24
|
+
"noUncheckedIndexedAccess": true,
|
|
25
|
+
"exactOptionalPropertyTypes": true,
|
|
26
|
+
|
|
27
|
+
// Style Options
|
|
28
|
+
// "noImplicitReturns": true,
|
|
29
|
+
// "noImplicitOverride": true,
|
|
30
|
+
// "noUnusedLocals": true,
|
|
31
|
+
// "noUnusedParameters": true,
|
|
32
|
+
// "noFallthroughCasesInSwitch": true,
|
|
33
|
+
// "noPropertyAccessFromIndexSignature": true,
|
|
34
|
+
|
|
35
|
+
// Recommended Options
|
|
36
|
+
"strict": true,
|
|
37
|
+
"jsx": "react-jsx",
|
|
38
|
+
"verbatimModuleSyntax": true,
|
|
39
|
+
"isolatedModules": true,
|
|
40
|
+
"noUncheckedSideEffectImports": true,
|
|
41
|
+
"moduleDetection": "force",
|
|
42
|
+
"skipLibCheck": true,
|
|
43
|
+
}
|
|
44
|
+
}
|