@semalt-ai/code 1.4.4 → 1.6.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/index.js +53 -1345
- package/lib/agent.js +81 -0
- package/lib/api.js +282 -0
- package/lib/args.js +45 -0
- package/lib/commands.js +344 -0
- package/lib/config.js +46 -0
- package/lib/constants.js +27 -0
- package/lib/context.js +71 -0
- package/lib/permissions.js +93 -0
- package/lib/prompts.js +29 -0
- package/lib/tools.js +120 -0
- package/lib/ui.js +603 -0
- package/package.json +1 -1
package/lib/tools.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { spawnSync } = require('child_process');
|
|
6
|
+
|
|
7
|
+
function createToolExecutor(permissionManager, ui) {
|
|
8
|
+
const { FG_DARK, FG_GRAY, FG_GREEN, FG_RED, RST } = ui;
|
|
9
|
+
|
|
10
|
+
async function agentExecShell(command) {
|
|
11
|
+
const approved = await permissionManager.askPermission('shell', command);
|
|
12
|
+
if (!approved) {
|
|
13
|
+
return { exit_code: -1, stdout: '', stderr: 'Permission denied by user' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
console.log(` ${FG_DARK}$ ${command}${RST}`);
|
|
17
|
+
try {
|
|
18
|
+
const result = spawnSync(command, { shell: true, encoding: 'utf8', timeout: 60000 });
|
|
19
|
+
const stdout = result.stdout || '';
|
|
20
|
+
const stderr = result.stderr || '';
|
|
21
|
+
const combined = stdout + (stderr ? `\n${stderr}` : '');
|
|
22
|
+
const lines = combined.trim().split('\n').filter((line) => line !== '');
|
|
23
|
+
|
|
24
|
+
if (lines.length > 20) {
|
|
25
|
+
lines.slice(0, 15).forEach((line) => console.log(` ${FG_GRAY}${line}${RST}`));
|
|
26
|
+
console.log(` ${FG_DARK}... (${lines.length - 15} more lines)${RST}`);
|
|
27
|
+
} else {
|
|
28
|
+
lines.forEach((line) => console.log(` ${FG_GRAY}${line}${RST}`));
|
|
29
|
+
}
|
|
30
|
+
console.log();
|
|
31
|
+
|
|
32
|
+
return { exit_code: result.status ?? 0, stdout, stderr };
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.log(` ${FG_RED}✗ ${error.message}${RST}`);
|
|
35
|
+
return { exit_code: -1, stdout: '', stderr: error.message };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function agentExecFile(action, filePath, content = null) {
|
|
40
|
+
if (action === 'read') {
|
|
41
|
+
const approved = await permissionManager.askPermission('file', `Read ${filePath}`);
|
|
42
|
+
if (!approved) return { error: 'Permission denied' };
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
const data = fs.readFileSync(filePath, 'utf8');
|
|
46
|
+
const lines = data.split('\n').length;
|
|
47
|
+
if (lines > 10) {
|
|
48
|
+
console.log(` ${FG_GREEN}✓${RST} ${FG_GRAY}Read ${filePath} (${lines} lines, ${data.length} chars)${RST}`);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(` ${FG_GREEN}✓${RST} ${FG_GRAY}Read ${filePath}${RST}`);
|
|
51
|
+
}
|
|
52
|
+
return { content: data, path: filePath };
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.log(` ${FG_RED}✗ ${error.message}${RST}`);
|
|
55
|
+
return { error: error.message };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (action === 'write' || action === 'append') {
|
|
60
|
+
let desc = `${action === 'write' ? 'Write' : 'Append to'} ${filePath}`;
|
|
61
|
+
if (content) desc += ` (${content.length} chars)`;
|
|
62
|
+
const approved = await permissionManager.askPermission('file', desc);
|
|
63
|
+
if (!approved) return { error: 'Permission denied' };
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const dir = path.dirname(filePath);
|
|
67
|
+
if (dir && dir !== '.') fs.mkdirSync(dir, { recursive: true });
|
|
68
|
+
if (action === 'write') fs.writeFileSync(filePath, content || '');
|
|
69
|
+
else fs.appendFileSync(filePath, content || '');
|
|
70
|
+
const verb = action === 'write' ? 'Wrote' : 'Appended to';
|
|
71
|
+
console.log(` ${FG_GREEN}✓${RST} ${FG_GRAY}${verb} ${filePath}${RST}`);
|
|
72
|
+
return { status: 'ok', path: filePath, bytes: (content || '').length };
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.log(` ${FG_RED}✗ ${error.message}${RST}`);
|
|
75
|
+
return { error: error.message };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return { error: `Unknown action: ${action}` };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
agentExecFile,
|
|
84
|
+
agentExecShell,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function extractToolCalls(text) {
|
|
89
|
+
const calls = [];
|
|
90
|
+
|
|
91
|
+
for (const match of text.matchAll(/```(?:shell|bash|sh)\n([\s\S]*?)```/g)) {
|
|
92
|
+
for (const line of match[1].trim().split('\n')) {
|
|
93
|
+
const cmd = line.trim();
|
|
94
|
+
if (cmd && !cmd.startsWith('#')) calls.push(['shell', cmd]);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
for (const match of text.matchAll(/<shell>([\s\S]*?)<\/shell>/g)) {
|
|
99
|
+
calls.push(['shell', match[1].trim()]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const match of text.matchAll(/<exec>([\s\S]*?)<\/exec>/g)) {
|
|
103
|
+
calls.push(['shell', match[1].trim()]);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
for (const match of text.matchAll(/<read_file>([\s\S]*?)<\/read_file>/g)) {
|
|
107
|
+
calls.push(['read', match[1].trim()]);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for (const match of text.matchAll(/<write_file\s+path="([^"]+)">([\s\S]*?)<\/write_file>/g)) {
|
|
111
|
+
calls.push(['write', match[1], match[2]]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return calls;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = {
|
|
118
|
+
createToolExecutor,
|
|
119
|
+
extractToolCalls,
|
|
120
|
+
};
|