uwonbot 1.2.2 → 1.2.4

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/agent.js +113 -47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uwonbot",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "Uwonbot AI Assistant CLI — Your AI controls your computer",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/agent.js CHANGED
@@ -85,17 +85,21 @@ async function loadNativeModules() {
85
85
  }
86
86
  console.log(chalk.green(' ✓ nut-js loaded (mouse/keyboard control)'));
87
87
  if (!accessOk) {
88
- console.log(chalk.yellow(' ⚠ 접근성 권한이 없어 마우스/키보드 제어가 제한될 수 있습니다.'));
88
+ console.log(chalk.yellow(' ⚠ 접근성 권한이 없어 CoreGraphics 폴백을 사용합니다.'));
89
89
  }
90
- } catch {
90
+ } catch (nutErr) {
91
91
  try {
92
92
  const rjs = await import('robotjs');
93
93
  robot = rjs.default || rjs;
94
94
  console.log(chalk.green(' ✓ robotjs loaded (mouse/keyboard control)'));
95
95
  } catch {
96
- console.log(chalk.yellow(' ⚠ No mouse/keyboard module found.'));
97
- console.log(chalk.yellow(' Install: npm install -g @nut-tree-fork/nut-js'));
98
96
  robot = null;
97
+ if (platform === 'darwin') {
98
+ console.log(chalk.green(' ✓ CoreGraphics 직접 제어 모드 (macOS 네이티브)'));
99
+ } else {
100
+ console.log(chalk.yellow(' ⚠ No mouse/keyboard module found.'));
101
+ console.log(chalk.yellow(' Install: npm install -g @nut-tree-fork/nut-js'));
102
+ }
99
103
  }
100
104
  }
101
105
 
@@ -129,10 +133,25 @@ async function getScreenSize() {
129
133
  return { width: 1920, height: 1080 };
130
134
  }
131
135
 
136
+ async function cgMoveMouse(px, py) {
137
+ await execAsync(`osascript -l JavaScript -e 'ObjC.import("CoreGraphics"); $.CGWarpMouseCursorPosition($.CGPointMake(${px}, ${py}))'`);
138
+ }
139
+
140
+ async function cgMouseEvent(eventType, px, py, mouseButton = 0) {
141
+ const script = `ObjC.import("CoreGraphics");
142
+ var pt = $.CGPointMake(${px}, ${py});
143
+ var e = $.CGEventCreateMouseEvent($(), ${eventType}, pt, ${mouseButton});
144
+ $.CGEventPost($.kCGHIDEventTap, e);`;
145
+ await execAsync(`osascript -l JavaScript -e '${script.replace(/\n/g, ' ')}'`);
146
+ }
147
+
148
+ let _lastKnownPos = { x: 960, y: 540 };
149
+
132
150
  async function moveMouse(x, y) {
133
151
  const screen = await getScreenSize();
134
152
  const px = Math.round(x * screen.width);
135
153
  const py = Math.round(y * screen.height);
154
+ _lastKnownPos = { x: px, y: py };
136
155
 
137
156
  try {
138
157
  if (robot?.mouse?.setPosition) {
@@ -143,9 +162,11 @@ async function moveMouse(x, y) {
143
162
  robot.moveMouse(px, py);
144
163
  return;
145
164
  }
146
- } catch {}
165
+ } catch (e) {
166
+ console.log(chalk.gray(` [mouse] nut-js fallback: ${e.message}`));
167
+ }
147
168
  if (platform === 'darwin') {
148
- try { await execAsync(`osascript -e 'tell application "System Events" to set position of mouse to {${px}, ${py}}'`); } catch {}
169
+ try { await cgMoveMouse(px, py); } catch {}
149
170
  }
150
171
  }
151
172
 
@@ -161,39 +182,86 @@ async function mouseClick(button = 'left', double = false) {
161
182
  robot.mouseClick(button, double);
162
183
  return;
163
184
  }
164
- } catch {}
185
+ } catch (e) {
186
+ console.log(chalk.gray(` [click] nut-js fallback: ${e.message}`));
187
+ }
165
188
  if (platform === 'darwin') {
166
- const clickType = button === 'right' ? 'right' : 'left';
167
- const script = `osascript -e 'tell application "System Events" to click'`;
168
- try { await execAsync(script); } catch {}
189
+ try {
190
+ const { x, y } = _lastKnownPos;
191
+ if (button === 'right') {
192
+ await cgMouseEvent('$.kCGEventRightMouseDown', x, y, '$.kCGMouseButtonRight');
193
+ await cgMouseEvent('$.kCGEventRightMouseUp', x, y, '$.kCGMouseButtonRight');
194
+ } else {
195
+ await cgMouseEvent('$.kCGEventLeftMouseDown', x, y, 0);
196
+ await cgMouseEvent('$.kCGEventLeftMouseUp', x, y, 0);
197
+ if (double) {
198
+ await new Promise(r => setTimeout(r, 50));
199
+ await cgMouseEvent('$.kCGEventLeftMouseDown', x, y, 0);
200
+ await cgMouseEvent('$.kCGEventLeftMouseUp', x, y, 0);
201
+ }
202
+ }
203
+ } catch {}
169
204
  }
170
205
  }
171
206
 
172
207
  async function mouseDown(button = 'left') {
173
- if (robot?.mouse?.pressButton) {
174
- const { Button } = await import('@nut-tree-fork/nut-js');
175
- await robot.mouse.pressButton(button === 'right' ? Button.RIGHT : Button.LEFT);
176
- } else if (robot?.mouseToggle) {
177
- robot.mouseToggle('down', button);
208
+ try {
209
+ if (robot?.mouse?.pressButton) {
210
+ const { Button } = await import('@nut-tree-fork/nut-js');
211
+ await robot.mouse.pressButton(button === 'right' ? Button.RIGHT : Button.LEFT);
212
+ return;
213
+ } else if (robot?.mouseToggle) {
214
+ robot.mouseToggle('down', button);
215
+ return;
216
+ }
217
+ } catch {}
218
+ if (platform === 'darwin') {
219
+ const { x, y } = _lastKnownPos;
220
+ try {
221
+ if (button === 'right') await cgMouseEvent('$.kCGEventRightMouseDown', x, y, '$.kCGMouseButtonRight');
222
+ else await cgMouseEvent('$.kCGEventLeftMouseDown', x, y, 0);
223
+ } catch {}
178
224
  }
179
225
  }
180
226
 
181
227
  async function mouseUp(button = 'left') {
182
- if (robot?.mouse?.releaseButton) {
183
- const { Button } = await import('@nut-tree-fork/nut-js');
184
- await robot.mouse.releaseButton(button === 'right' ? Button.RIGHT : Button.LEFT);
185
- } else if (robot?.mouseToggle) {
186
- robot.mouseToggle('up', button);
228
+ try {
229
+ if (robot?.mouse?.releaseButton) {
230
+ const { Button } = await import('@nut-tree-fork/nut-js');
231
+ await robot.mouse.releaseButton(button === 'right' ? Button.RIGHT : Button.LEFT);
232
+ return;
233
+ } else if (robot?.mouseToggle) {
234
+ robot.mouseToggle('up', button);
235
+ return;
236
+ }
237
+ } catch {}
238
+ if (platform === 'darwin') {
239
+ const { x, y } = _lastKnownPos;
240
+ try {
241
+ if (button === 'right') await cgMouseEvent('$.kCGEventRightMouseUp', x, y, '$.kCGMouseButtonRight');
242
+ else await cgMouseEvent('$.kCGEventLeftMouseUp', x, y, 0);
243
+ } catch {}
187
244
  }
188
245
  }
189
246
 
190
247
  async function mouseScroll(dx, dy) {
191
- if (robot?.mouse?.scrollDown && robot?.mouse?.scrollUp) {
192
- const amount = Math.abs(dy);
193
- if (dy > 0) await robot.mouse.scrollDown(amount);
194
- else await robot.mouse.scrollUp(amount);
195
- } else if (robot?.scrollMouse) {
196
- robot.scrollMouse(dx, dy);
248
+ try {
249
+ if (robot?.mouse?.scrollDown && robot?.mouse?.scrollUp) {
250
+ const amount = Math.abs(dy);
251
+ if (dy > 0) await robot.mouse.scrollDown(amount);
252
+ else await robot.mouse.scrollUp(amount);
253
+ return;
254
+ } else if (robot?.scrollMouse) {
255
+ robot.scrollMouse(dx, dy);
256
+ return;
257
+ }
258
+ } catch {}
259
+ if (platform === 'darwin') {
260
+ const lines = Math.round(dy / 10) || (dy > 0 ? 1 : -1);
261
+ try {
262
+ const script = `ObjC.import("CoreGraphics"); var e = $.CGEventCreateScrollWheelEvent($(), 0, 1, ${-lines}); $.CGEventPost($.kCGHIDEventTap, e);`;
263
+ await execAsync(`osascript -l JavaScript -e '${script}'`);
264
+ } catch {}
197
265
  }
198
266
  }
199
267
 
@@ -207,10 +275,18 @@ async function mouseDrag(fromX, fromY, toX, toY) {
207
275
  }
208
276
 
209
277
  async function typeText(text) {
210
- if (robot?.keyboard?.type) {
211
- await robot.keyboard.type(text);
212
- } else if (robot?.typeString) {
213
- robot.typeString(text);
278
+ try {
279
+ if (robot?.keyboard?.type) {
280
+ await robot.keyboard.type(text);
281
+ return;
282
+ } else if (robot?.typeString) {
283
+ robot.typeString(text);
284
+ return;
285
+ }
286
+ } catch {}
287
+ if (platform === 'darwin') {
288
+ const escaped = text.replace(/'/g, "'\\''").replace(/"/g, '\\"');
289
+ try { await execAsync(`osascript -e 'tell application "System Events" to keystroke "${escaped}"'`); } catch {}
214
290
  }
215
291
  }
216
292
 
@@ -513,10 +589,10 @@ async function openWebAssistant(assistantId) {
513
589
 
514
590
  async function activateAllAssistants(assistants) {
515
591
  const opened = [];
516
- for (const a of assistants) {
517
- await openWebAssistant(a.id);
518
- opened.push({ name: a.name, mode: 'web' });
519
- await new Promise(r => setTimeout(r, 500));
592
+ const first = assistants[0];
593
+ if (first) {
594
+ await openWebAssistant(first.id);
595
+ opened.push({ name: first.name, mode: 'web' });
520
596
  }
521
597
  return opened;
522
598
  }
@@ -632,19 +708,9 @@ export async function startAgent(port = 9876, options = {}) {
632
708
  return;
633
709
  }
634
710
 
635
- console.log(chalk.cyan(` → ${userAssistants.length}개 비서 모두 활성화`));
636
- const opened = await activateAllAssistants(userAssistants);
637
- opened.forEach(o => {
638
- console.log(chalk.gray(` ✓ ${o.name} (${o.mode})`));
639
- });
640
-
641
- const geminiKey = userAssistants.find(a => a.apiKey)?.apiKey;
642
- if (geminiKey) {
643
- await listenForName(userAssistants, geminiKey);
644
- } else {
645
- console.log(chalk.gray(' → 모든 비서가 활성 상태로 유지됩니다.'));
646
- console.log(chalk.gray(' (비서 이름을 말해 선택하려면 API 키가 필요합니다)'));
647
- }
711
+ const first = userAssistants[0];
712
+ console.log(chalk.green(` → ${first.name} 실행 (비서 ${userAssistants.length}개 중 첫 번째)`));
713
+ await openWebAssistant(first.id);
648
714
  });
649
715
  await clapListener.start();
650
716
  console.log('');