natureco-cli 5.16.0 → 5.16.1
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/package.json +1 -1
- package/src/tools/computer_use.js +210 -57
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "natureco-cli",
|
|
3
|
-
"version": "5.16.
|
|
3
|
+
"version": "5.16.1",
|
|
4
4
|
"description": "OpenClaw'dan daha güvenli, daha hızlı, daha ucuz AI agent CLI. Multi-agent, self-evolving skills, audit log, maliyet optimizasyonu ve NatureCo platform-native.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"natureco": "bin/natureco.js"
|
|
@@ -1,138 +1,291 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { spawnSync } = require('child_process');
|
|
2
2
|
const os = require('os');
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
|
|
6
6
|
const PLATFORM = os.platform();
|
|
7
7
|
|
|
8
|
+
const KEY_MAP_DARWIN = {
|
|
9
|
+
enter: 'return',
|
|
10
|
+
return: 'return',
|
|
11
|
+
tab: 'tab',
|
|
12
|
+
escape: 'escape',
|
|
13
|
+
esc: 'escape',
|
|
14
|
+
up: 'up',
|
|
15
|
+
down: 'down',
|
|
16
|
+
left: 'left',
|
|
17
|
+
right: 'right',
|
|
18
|
+
backspace: 'delete',
|
|
19
|
+
delete: 'forwarddelete',
|
|
20
|
+
forwarddelete: 'forwarddelete',
|
|
21
|
+
home: 'home',
|
|
22
|
+
end: 'end',
|
|
23
|
+
pageup: 'page up',
|
|
24
|
+
pagedown: 'page down',
|
|
25
|
+
space: 'space',
|
|
26
|
+
' ': 'space',
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const MODIFIER_MAP = {
|
|
30
|
+
command: 'command down',
|
|
31
|
+
cmd: 'command down',
|
|
32
|
+
option: 'option down',
|
|
33
|
+
alt: 'option down',
|
|
34
|
+
control: 'control down',
|
|
35
|
+
ctrl: 'control down',
|
|
36
|
+
shift: 'shift down',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function escapeText(s) {
|
|
40
|
+
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function osaScript(script, timeoutMs = 10000) {
|
|
44
|
+
const result = spawnSync('osascript', ['-e', script], {
|
|
45
|
+
timeout: timeoutMs,
|
|
46
|
+
encoding: 'utf8',
|
|
47
|
+
maxBuffer: 1024 * 1024,
|
|
48
|
+
});
|
|
49
|
+
if (result.error) {
|
|
50
|
+
if (result.error.code === 'ETIMEDOUT') {
|
|
51
|
+
return { success: false, error: 'osascript timed out after ' + timeoutMs + 'ms' };
|
|
52
|
+
}
|
|
53
|
+
return { success: false, error: result.error.message };
|
|
54
|
+
}
|
|
55
|
+
if (result.status !== 0) {
|
|
56
|
+
const msg = result.stderr || result.stdout || 'unknown error';
|
|
57
|
+
let friendly = msg;
|
|
58
|
+
if (msg.includes('yardımcı erişime izin verilmiyor') || msg.includes('access for assistive devices')) {
|
|
59
|
+
friendly = 'Accessibility izni gerekli. System Settings > Privacy & Security > Accessibility > Terminal/iTerm2\'ye izin verin.';
|
|
60
|
+
} else if (msg.includes('(-1700') || msg.includes('can\'t convert')) {
|
|
61
|
+
friendly = 'AppleScript hatasi: ' + msg.slice(0, 200);
|
|
62
|
+
}
|
|
63
|
+
return { success: false, error: friendly };
|
|
64
|
+
}
|
|
65
|
+
return { success: true, data: result.stdout };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function checkAccessibility() {
|
|
69
|
+
const r = osaScript('tell application "System Events" to get name of first process whose frontmost is true', 3000);
|
|
70
|
+
return r.success;
|
|
71
|
+
}
|
|
72
|
+
|
|
8
73
|
async function computerUse(params) {
|
|
9
|
-
const { action, x, y, key, text, button, clicks,
|
|
74
|
+
const { action, x, y, key, text, button, clicks, file } = params;
|
|
10
75
|
|
|
11
76
|
if (action === 'screenshot') {
|
|
12
77
|
const outputFile = file || path.join(os.tmpdir(), 'natureco_screen_' + Date.now() + '.png');
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
78
|
+
try {
|
|
79
|
+
if (PLATFORM === 'darwin') {
|
|
80
|
+
spawnSync('screencapture', ['-x', outputFile], { timeout: 5000 });
|
|
81
|
+
} else if (PLATFORM === 'win32') {
|
|
82
|
+
spawnSync('powershell', ['-Command',
|
|
83
|
+
'Add-Type -AssemblyName System.Windows.Forms; ' +
|
|
84
|
+
'$bmp = [System.Drawing.Bitmap]::new([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height); ' +
|
|
85
|
+
'$g = [System.Drawing.Graphics]::FromImage($bmp); ' +
|
|
86
|
+
'$g.CopyFromScreen(0, 0, 0, 0, $bmp.Size); ' +
|
|
87
|
+
'$bmp.Save("' + outputFile.replace(/"/g, '') + '", [System.Drawing.Imaging.ImageFormat]::Png)'
|
|
88
|
+
], { timeout: 10000 });
|
|
89
|
+
} else {
|
|
90
|
+
spawnSync('import', ['-window', 'root', outputFile], { timeout: 5000 });
|
|
91
|
+
}
|
|
92
|
+
return { success: true, file: outputFile, platform: PLATFORM, note: 'Ekran goruntusu alindi' };
|
|
93
|
+
} catch (e) {
|
|
94
|
+
return { success: false, error: 'Screenshot hatasi: ' + e.message };
|
|
19
95
|
}
|
|
20
|
-
return { success: true, file: outputFile, platform: PLATFORM, note: 'Ekran goruntusu alindi: ' + outputFile };
|
|
21
96
|
}
|
|
22
97
|
|
|
23
98
|
if (action === 'click') {
|
|
24
99
|
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y gerekli' };
|
|
25
100
|
const btn = button || 'left';
|
|
26
101
|
if (PLATFORM === 'darwin') {
|
|
27
|
-
|
|
28
|
-
|
|
102
|
+
const acc = checkAccessibility();
|
|
103
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli. System Settings > Privacy & Security > Accessibility > Terminal\'e izin verin.' };
|
|
104
|
+
const r = osaScript('tell application "System Events" to click at {' + x + ', ' + y + '}');
|
|
105
|
+
if (!r.success) return r;
|
|
106
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
107
|
+
}
|
|
108
|
+
if (PLATFORM === 'win32') {
|
|
29
109
|
const c = clicks || 1;
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
110
|
+
spawnSync('powershell', ['-Command',
|
|
111
|
+
'[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + '); ' +
|
|
112
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + (c > 1 ? '{DOUBLECLICK}' : '{CLICK}') + '")'
|
|
113
|
+
], { timeout: 5000 });
|
|
114
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
33
115
|
}
|
|
34
|
-
|
|
116
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y), 'click', '1'], { timeout: 5000 });
|
|
117
|
+
return { success: true, action: 'click', x, y, button: btn };
|
|
35
118
|
}
|
|
36
119
|
|
|
37
120
|
if (action === 'type') {
|
|
38
121
|
if (!text) return { success: false, error: 'text gerekli' };
|
|
39
122
|
if (PLATFORM === 'darwin') {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
123
|
+
const acc = checkAccessibility();
|
|
124
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
125
|
+
const r = osaScript('tell application "System Events" to keystroke "' + escapeText(text) + '"');
|
|
126
|
+
if (!r.success) return r;
|
|
127
|
+
return { success: true, action: 'type', text };
|
|
128
|
+
}
|
|
129
|
+
if (PLATFORM === 'win32') {
|
|
130
|
+
spawnSync('powershell', ['-Command',
|
|
131
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + text.replace(/[{}()^+% ~]/g, '{$&}') + '")'
|
|
132
|
+
], { timeout: 5000 });
|
|
133
|
+
return { success: true, action: 'type', text };
|
|
46
134
|
}
|
|
135
|
+
spawnSync('xdotool', ['type', text], { timeout: 5000 });
|
|
47
136
|
return { success: true, action: 'type', text };
|
|
48
137
|
}
|
|
49
138
|
|
|
50
139
|
if (action === 'keypress') {
|
|
51
140
|
if (!key) return { success: false, error: 'key gerekli' };
|
|
52
141
|
if (PLATFORM === 'darwin') {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
142
|
+
const acc = checkAccessibility();
|
|
143
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
144
|
+
|
|
145
|
+
const parts = key.toLowerCase().split('+').map(p => p.trim());
|
|
146
|
+
const mods = [];
|
|
147
|
+
let actualKey = '';
|
|
148
|
+
for (const p of parts) {
|
|
149
|
+
if (MODIFIER_MAP[p]) mods.push(MODIFIER_MAP[p]);
|
|
150
|
+
else actualKey = p;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (KEY_MAP_DARWIN[actualKey]) {
|
|
154
|
+
const keyName = KEY_MAP_DARWIN[actualKey];
|
|
155
|
+
const usingClause = mods.length > 0 ? ' using {' + mods.join(', ') + '}' : '';
|
|
156
|
+
const r = osaScript('tell application "System Events" to keystroke ' + keyName + usingClause);
|
|
157
|
+
if (!r.success) return r;
|
|
158
|
+
} else if (actualKey) {
|
|
159
|
+
const usingClause = mods.length > 0 ? ' using {' + mods.join(', ') + '}' : '';
|
|
160
|
+
const r = osaScript('tell application "System Events" to keystroke "' + escapeText(actualKey) + '"' + usingClause);
|
|
161
|
+
if (!r.success) return r;
|
|
162
|
+
} else {
|
|
163
|
+
if (mods.length > 0) {
|
|
164
|
+
return { success: false, error: 'Modifier-only keypress not supported. Provide a key with modifiers (e.g. cmd+q).' };
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return { success: true, action: 'keypress', key };
|
|
61
168
|
}
|
|
169
|
+
if (PLATFORM === 'win32') {
|
|
170
|
+
const keyMap = {
|
|
171
|
+
enter: '{ENTER}', tab: '{TAB}', escape: '{ESC}', up: '{UP}', down: '{DOWN}',
|
|
172
|
+
left: '{LEFT}', right: '{RIGHT}', backspace: '{BACKSPACE}', delete: '{DELETE}',
|
|
173
|
+
home: '{HOME}', end: '{END}', pageup: '{PGUP}', pagedown: '{PGDN}',
|
|
174
|
+
};
|
|
175
|
+
spawnSync('powershell', ['-Command',
|
|
176
|
+
'[System.Windows.Forms.SendKeys]::SendWait("' + (keyMap[key.toLowerCase()] || key) + '")'
|
|
177
|
+
], { timeout: 5000 });
|
|
178
|
+
return { success: true, action: 'keypress', key };
|
|
179
|
+
}
|
|
180
|
+
spawnSync('xdotool', ['key', key], { timeout: 5000 });
|
|
62
181
|
return { success: true, action: 'keypress', key };
|
|
63
182
|
}
|
|
64
183
|
|
|
65
184
|
if (action === 'mouse_move') {
|
|
66
185
|
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y gerekli' };
|
|
67
186
|
if (PLATFORM === 'darwin') {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
187
|
+
const acc = checkAccessibility();
|
|
188
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
189
|
+
const r = osaScript('tell application "System Events" to set position of mouse to {' + x + ', ' + y + '}');
|
|
190
|
+
if (!r.success) return r;
|
|
191
|
+
return { success: true, action: 'mouse_move', x, y };
|
|
192
|
+
}
|
|
193
|
+
if (PLATFORM === 'win32') {
|
|
194
|
+
spawnSync('powershell', ['-Command',
|
|
195
|
+
'[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + ')'
|
|
196
|
+
], { timeout: 5000 });
|
|
197
|
+
return { success: true, action: 'mouse_move', x, y };
|
|
73
198
|
}
|
|
199
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y)], { timeout: 5000 });
|
|
74
200
|
return { success: true, action: 'mouse_move', x, y };
|
|
75
201
|
}
|
|
76
202
|
|
|
77
203
|
if (action === 'mouse_position') {
|
|
78
204
|
if (PLATFORM === 'darwin') {
|
|
79
|
-
const
|
|
80
|
-
|
|
205
|
+
const r = osaScript('tell application "System Events" to return position of mouse');
|
|
206
|
+
if (!r.success) return r;
|
|
207
|
+
const [mx, my] = r.data.trim().split(', ').map(Number);
|
|
81
208
|
return { success: true, x: mx, y: my };
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const
|
|
88
|
-
const mx = parseInt(out.match(/x:(\d+)/)?.[1] || '0');
|
|
89
|
-
const my = parseInt(out.match(/y:(\d+)/)?.[1] || '0');
|
|
209
|
+
}
|
|
210
|
+
if (PLATFORM === 'win32') {
|
|
211
|
+
const result = spawnSync('powershell', ['-Command',
|
|
212
|
+
'[System.Windows.Forms.Cursor]::Position.X.ToString() + ", " + [System.Windows.Forms.Cursor]::Position.Y.ToString()'
|
|
213
|
+
], { timeout: 5000, encoding: 'utf8' });
|
|
214
|
+
const [mx, my] = result.stdout.trim().split(', ').map(Number);
|
|
90
215
|
return { success: true, x: mx, y: my };
|
|
91
216
|
}
|
|
217
|
+
const result = spawnSync('xdotool', ['getmouselocation'], { timeout: 5000, encoding: 'utf8' });
|
|
218
|
+
const mx = parseInt(result.stdout.match(/x:(\d+)/)?.[1] || '0');
|
|
219
|
+
const my = parseInt(result.stdout.match(/y:(\d+)/)?.[1] || '0');
|
|
220
|
+
return { success: true, x: mx, y: my };
|
|
92
221
|
}
|
|
93
222
|
|
|
94
223
|
if (action === 'scroll') {
|
|
95
224
|
if (typeof y !== 'number') return { success: false, error: 'y (pixels) gerekli' };
|
|
96
225
|
if (PLATFORM === 'darwin') {
|
|
97
|
-
|
|
98
|
-
return { success:
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
226
|
+
const acc = checkAccessibility();
|
|
227
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
228
|
+
const direction = y > 0 ? 'up' : 'down';
|
|
229
|
+
const times = Math.abs(Math.ceil(y / 40));
|
|
230
|
+
const r = osaScript('tell application "System Events" to repeat ' + times + ' times\n key code 125\nend repeat');
|
|
231
|
+
if (!r.success) return r;
|
|
232
|
+
|
|
233
|
+
return { success: true, action: 'scroll', y, note: 'Scrolled ' + direction + ' ' + times + ' steps' };
|
|
234
|
+
}
|
|
235
|
+
spawnSync('xdotool', ['click', y < 0 ? '4' : '5', '--repeat', String(Math.abs(Math.ceil(y / 50)))], { timeout: 5000 });
|
|
236
|
+
return { success: true, action: 'scroll', y };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (action === 'drag') {
|
|
240
|
+
if (typeof x !== 'number' || typeof y !== 'number') return { success: false, error: 'x ve y (baslangic) gerekli' };
|
|
241
|
+
const x2 = params.x2, y2 = params.y2;
|
|
242
|
+
if (typeof x2 !== 'number' || typeof y2 !== 'number') return { success: false, error: 'x2 ve y2 (bitis) gerekli' };
|
|
243
|
+
if (PLATFORM === 'darwin') {
|
|
244
|
+
const acc = checkAccessibility();
|
|
245
|
+
if (!acc) return { success: false, error: 'Accessibility izni gerekli' };
|
|
246
|
+
const r = osaScript('tell application "System Events"\n set mousePos to {' + x + ', ' + y + '}\n set mousePos2 to {' + x2 + ', ' + y2 + '}\n set position of mouse to mousePos\n delay 0.1\n mouse down\n set position of mouse to mousePos2\n delay 0.1\n mouse up\nend tell');
|
|
247
|
+
if (!r.success) return r;
|
|
248
|
+
return { success: true, action: 'drag', from: { x, y }, to: { x: x2, y: y2 } };
|
|
249
|
+
}
|
|
250
|
+
if (PLATFORM === 'linux') {
|
|
251
|
+
spawnSync('xdotool', ['mousemove', String(x), String(y), 'mousedown', '1', 'mousemove', String(x2), String(y2), 'mouseup', '1'], { timeout: 5000 });
|
|
252
|
+
return { success: true, action: 'drag', from: { x, y }, to: { x: x2, y: y2 } };
|
|
102
253
|
}
|
|
254
|
+
return { success: false, error: 'drag only supported on macOS and Linux' };
|
|
103
255
|
}
|
|
104
256
|
|
|
105
257
|
if (action === 'info') {
|
|
106
258
|
const displays = [];
|
|
107
259
|
try {
|
|
108
260
|
if (PLATFORM === 'darwin') {
|
|
109
|
-
const
|
|
110
|
-
for (const line of
|
|
261
|
+
const result = spawnSync('system_profiler', ['SPDisplaysDataType'], { timeout: 5000, encoding: 'utf8' });
|
|
262
|
+
for (const line of result.stdout.split('\n')) {
|
|
111
263
|
const m = line.match(/(\d+) x (\d+)/);
|
|
112
264
|
if (m) displays.push({ width: parseInt(m[1]), height: parseInt(m[2]) });
|
|
113
265
|
}
|
|
114
266
|
}
|
|
115
267
|
} catch {}
|
|
116
|
-
return { success: true, platform: PLATFORM, displays: displays.length > 0 ? displays : undefined
|
|
268
|
+
return { success: true, platform: PLATFORM, displays: displays.length > 0 ? displays : undefined };
|
|
117
269
|
}
|
|
118
270
|
|
|
119
|
-
return { success: false, error: 'Gecersiz action: ' + action + ' (screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info)' };
|
|
271
|
+
return { success: false, error: 'Gecersiz action: ' + action + ' (screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info)' };
|
|
120
272
|
}
|
|
121
273
|
|
|
122
274
|
module.exports = {
|
|
123
275
|
name: 'computer_use',
|
|
124
|
-
description: 'GUI otomasyonu: screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info. macOS/Windows/Linux.',
|
|
276
|
+
description: 'GUI otomasyonu: screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info. macOS/Windows/Linux.',
|
|
125
277
|
inputSchema: {
|
|
126
278
|
type: 'object',
|
|
127
279
|
properties: {
|
|
128
|
-
action: { type: 'string', description: 'screenshot, click, type, keypress, mouse_move, mouse_position, scroll, info', enum: ['screenshot', 'click', 'type', 'keypress', 'mouse_move', 'mouse_position', 'scroll', 'info'] },
|
|
280
|
+
action: { type: 'string', description: 'screenshot, click, type, keypress, mouse_move, mouse_position, scroll, drag, info', enum: ['screenshot', 'click', 'type', 'keypress', 'mouse_move', 'mouse_position', 'scroll', 'drag', 'info'] },
|
|
129
281
|
x: { type: 'number', description: 'X koordinati' },
|
|
130
282
|
y: { type: 'number', description: 'Y koordinati' },
|
|
131
283
|
button: { type: 'string', description: 'Fare tusu: left, right, middle (default: left)' },
|
|
132
284
|
clicks: { type: 'number', description: 'Tiklama sayisi (default: 1)' },
|
|
133
|
-
key: { type: 'string', description: '(keypress) Tus adi: enter, tab, escape, up, down, left, right, backspace, delete' },
|
|
285
|
+
key: { type: 'string', description: '(keypress) Tus adi veya kombinasyon: enter, tab, escape, up, down, left, right, backspace, delete, cmd+q, cmd+shift+z, alt+space' },
|
|
286
|
+
x2: { type: 'number', description: '(drag) Bitis X koordinati' },
|
|
287
|
+
y2: { type: 'number', description: '(drag) Bitis Y koordinati' },
|
|
134
288
|
text: { type: 'string', description: '(type) Yazilacak metin' },
|
|
135
|
-
query: { type: 'string', description: 'Arama sorgusu' },
|
|
136
289
|
file: { type: 'string', description: '(screenshot) Kayit dosyasi' },
|
|
137
290
|
},
|
|
138
291
|
required: ['action'],
|