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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "natureco-cli",
3
- "version": "5.16.0",
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 { spawn, execSync } = require('child_process');
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, query, file } = params;
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
- if (PLATFORM === 'darwin') {
14
- execSync('screencapture -x "' + outputFile + '"', { timeout: 5000 });
15
- } else if (PLATFORM === 'win32') {
16
- execSync('powershell -Command "Add-Type -AssemblyName System.Windows.Forms; $bmp = [System.Drawing.Bitmap]::new([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height); $g = [System.Drawing.Graphics]::FromImage($bmp); $g.CopyFromScreen(0, 0, 0, 0, $bmp.Size); $bmp.Save(\\"' + outputFile + '\\", [System.Drawing.Imaging.ImageFormat]::Png)"', { timeout: 10000 });
17
- } else {
18
- execSync('import -window root "' + outputFile + '"', { timeout: 5000 });
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
- execSync('osascript -e \'tell application "System Events" to click at {' + x + ', ' + y + '}\'', { timeout: 5000 });
28
- } else if (PLATFORM === 'win32') {
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
- execSync('powershell -Command "[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + '); [System.Windows.Forms.SendKeys]::SendWait(\\"' + (c > 1 ? '{DOUBLECLICK}' : '{CLICK}') + '\\")"', { timeout: 5000 });
31
- } else {
32
- execSync('xdotool mousemove ' + x + ' ' + y + ' click 1', { timeout: 5000 });
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
- return { success: true, action: 'click', x, y, button };
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 safeText = text.replace(/"/g, '\\"');
41
- execSync('osascript -e \'tell application "System Events" to keystroke "' + safeText + '"\'', { timeout: 5000 });
42
- } else if (PLATFORM === 'win32') {
43
- execSync('powershell -Command "[System.Windows.Forms.SendKeys]::SendWait(\\"' + text.replace(/[{}()^+% ~]/g, '{$&}') + '\\")"', { timeout: 5000 });
44
- } else {
45
- execSync('xdotool type "' + text.replace(/"/g, '\\"') + '"', { timeout: 5000 });
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 keyMap = { enter: 'return', tab: 'tab', escape: 'escape', up: 'up', down: 'down', left: 'left', right: 'right', backspace: 'delete', delete: 'forwarddelete' };
54
- const k = keyMap[key.toLowerCase()] || key;
55
- execSync('osascript -e \'tell application "System Events" to key code ' + (isNaN(k) ? '"' + k + '"' : k) + '\'', { timeout: 5000 });
56
- } else if (PLATFORM === 'win32') {
57
- const keyMap = { enter: '{ENTER}', tab: '{TAB}', escape: '{ESC}', up: '{UP}', down: '{DOWN}', left: '{LEFT}', right: '{RIGHT}', backspace: '{BACKSPACE}', delete: '{DELETE}' };
58
- execSync('powershell -Command "[System.Windows.Forms.SendKeys]::SendWait(\\"' + (keyMap[key.toLowerCase()] || key) + '\\")"', { timeout: 5000 });
59
- } else {
60
- execSync('xdotool key ' + key, { timeout: 5000 });
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
- execSync('osascript -e \'tell application "System Events" to set position of mouse to {' + x + ', ' + y + '}\'', { timeout: 5000 });
69
- } else if (PLATFORM === 'win32') {
70
- execSync('powershell -Command "[System.Windows.Forms.Cursor]::Position = New-Object System.Drawing.Point(' + x + ', ' + y + ')"', { timeout: 5000 });
71
- } else {
72
- execSync('xdotool mousemove ' + x + ' ' + y, { timeout: 5000 });
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 out = execSync('osascript -e \'tell application "System Events" to return position of mouse\'', { timeout: 5000 }).toString().trim();
80
- const [mx, my] = out.split(', ').map(Number);
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
- } else if (PLATFORM === 'win32') {
83
- const out = execSync('powershell -Command "[System.Windows.Forms.Cursor]::Position.X.ToString() + \\", \\" + [System.Windows.Forms.Cursor]::Position.Y.ToString()"', { timeout: 5000 }).toString().trim();
84
- const [mx, my] = out.split(', ').map(Number);
85
- return { success: true, x: mx, y: my };
86
- } else {
87
- const out = execSync('xdotool getmouselocation', { timeout: 5000 }).toString().trim();
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
- execSync('osascript -e \'tell application "System Events" to scroll (current application)\' &', { timeout: 5000 }); // simplified
98
- return { success: true, action: 'scroll', y, note: 'macOS scroll icin Accessibility izni gerekli' };
99
- } else {
100
- execSync('xdotool click ' + (y < 0 ? '4' : '5') + ' --repeat ' + Math.abs(Math.ceil(y / 50)), { timeout: 5000 });
101
- return { success: true, action: 'scroll', y };
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 out = execSync('system_profiler SPDisplaysDataType 2>/dev/null | grep Resolution', { timeout: 5000 }).toString();
110
- for (const line of out.trim().split('\n')) {
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, note: 'Ekran bilgisi' };
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'],