clawmate 1.4.2 → 1.5.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/main/ai-bridge.js +12 -0
- package/main/autostart.js +69 -2
- package/main/index.js +13 -2
- package/main/ipc-handlers.js +24 -1
- package/main/platform.js +17 -1
- package/main/proactive-monitor.js +1009 -0
- package/main/tray.js +26 -1
- package/package.json +1 -1
- package/preload/preload.js +7 -0
- package/renderer/index.html +1 -0
- package/renderer/js/app.js +5 -0
- package/renderer/js/browser-watcher.js +6 -0
- package/renderer/js/proactive-controller.js +205 -0
- package/shared/messages.js +408 -0
- package/skills/launch-pet/index.js +86 -4
package/shared/messages.js
CHANGED
|
@@ -195,6 +195,414 @@ const MESSAGES = {
|
|
|
195
195
|
},
|
|
196
196
|
},
|
|
197
197
|
|
|
198
|
+
// Proactive trigger messages (pet reacts to user activity patterns)
|
|
199
|
+
proactive: {
|
|
200
|
+
// Clipboard triggers
|
|
201
|
+
clipboard_copy: {
|
|
202
|
+
messages: [
|
|
203
|
+
'Ooh, what did you copy?',
|
|
204
|
+
'Ctrl+C ninja!',
|
|
205
|
+
'Copied something interesting?',
|
|
206
|
+
'What\'s that you grabbed?',
|
|
207
|
+
],
|
|
208
|
+
emotion: 'curious',
|
|
209
|
+
},
|
|
210
|
+
clipboard_screenshot: {
|
|
211
|
+
messages: [
|
|
212
|
+
'Screenshot! What\'s that for?',
|
|
213
|
+
'Saving memories?',
|
|
214
|
+
'Nice capture!',
|
|
215
|
+
'Taking screenshots, huh?',
|
|
216
|
+
],
|
|
217
|
+
emotion: 'excited',
|
|
218
|
+
},
|
|
219
|
+
repeated_copy: {
|
|
220
|
+
messages: [
|
|
221
|
+
'You\'re copying a lot... researching something?',
|
|
222
|
+
'Copy-paste marathon!',
|
|
223
|
+
'Collecting data? I see you!',
|
|
224
|
+
],
|
|
225
|
+
emotion: 'curious',
|
|
226
|
+
},
|
|
227
|
+
url_copied: {
|
|
228
|
+
messages: [
|
|
229
|
+
'Sharing a link? Who\'s the lucky one?',
|
|
230
|
+
'Got a good link there?',
|
|
231
|
+
'URL copied! Sending it somewhere?',
|
|
232
|
+
],
|
|
233
|
+
emotion: 'curious',
|
|
234
|
+
},
|
|
235
|
+
code_copied: {
|
|
236
|
+
messages: [
|
|
237
|
+
'Copying code? Stack Overflow approved!',
|
|
238
|
+
'Good developers copy, great developers paste!',
|
|
239
|
+
'Ctrl+C from Stack Overflow... classic!',
|
|
240
|
+
],
|
|
241
|
+
emotion: 'playful',
|
|
242
|
+
},
|
|
243
|
+
long_text_copied: {
|
|
244
|
+
messages: [
|
|
245
|
+
'That\'s a lot of text!',
|
|
246
|
+
'Writing an essay?',
|
|
247
|
+
'Big copy! Must be important.',
|
|
248
|
+
],
|
|
249
|
+
emotion: 'curious',
|
|
250
|
+
},
|
|
251
|
+
email_copied: {
|
|
252
|
+
messages: [
|
|
253
|
+
'Got an email address? Making contacts!',
|
|
254
|
+
'Email copied! Important person?',
|
|
255
|
+
],
|
|
256
|
+
emotion: 'neutral',
|
|
257
|
+
},
|
|
258
|
+
phone_copied: {
|
|
259
|
+
messages: [
|
|
260
|
+
'Phone number! Calling someone?',
|
|
261
|
+
'Got a number there!',
|
|
262
|
+
],
|
|
263
|
+
emotion: 'neutral',
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
// App/window triggers
|
|
267
|
+
app_switch: {
|
|
268
|
+
messages: [
|
|
269
|
+
'Switching gears!',
|
|
270
|
+
'On to something new?',
|
|
271
|
+
'Task hopping~',
|
|
272
|
+
],
|
|
273
|
+
emotion: 'neutral',
|
|
274
|
+
},
|
|
275
|
+
error_detected: {
|
|
276
|
+
messages: [
|
|
277
|
+
'Uh oh, I see an error!',
|
|
278
|
+
'Error detected! Need help?',
|
|
279
|
+
'Something broke? Don\'t worry, you got this!',
|
|
280
|
+
'Bug alert! Time to debug~',
|
|
281
|
+
],
|
|
282
|
+
emotion: 'scared',
|
|
283
|
+
},
|
|
284
|
+
error_loop: {
|
|
285
|
+
messages: [
|
|
286
|
+
'Same error again? Let me cheer you on!',
|
|
287
|
+
'Debugging is tough... hang in there!',
|
|
288
|
+
'Maybe try a different approach?',
|
|
289
|
+
'Have you tried turning it off and on again?',
|
|
290
|
+
],
|
|
291
|
+
emotion: 'worried',
|
|
292
|
+
},
|
|
293
|
+
meeting_detected: {
|
|
294
|
+
messages: [
|
|
295
|
+
'Meeting time! Good luck!',
|
|
296
|
+
'On a call? I\'ll be quiet...',
|
|
297
|
+
'Meeting mode activated. *whispers*',
|
|
298
|
+
],
|
|
299
|
+
emotion: 'neutral',
|
|
300
|
+
},
|
|
301
|
+
rapid_switching: {
|
|
302
|
+
messages: [
|
|
303
|
+
'Whoa, slow down! So many windows!',
|
|
304
|
+
'Tab switching speedrun?',
|
|
305
|
+
'Can\'t decide what to focus on?',
|
|
306
|
+
],
|
|
307
|
+
emotion: 'excited',
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
// Site category triggers
|
|
311
|
+
shopping_detected: {
|
|
312
|
+
messages: [
|
|
313
|
+
'Shopping time? Watch that wallet!',
|
|
314
|
+
'What are you buying? Show me!',
|
|
315
|
+
'Window shopping or actually buying?',
|
|
316
|
+
'Your cart is watching you...',
|
|
317
|
+
],
|
|
318
|
+
emotion: 'excited',
|
|
319
|
+
},
|
|
320
|
+
checkout_detected: {
|
|
321
|
+
messages: [
|
|
322
|
+
'About to checkout! Are you sure you need it?',
|
|
323
|
+
'Wait! Think about it one more time~',
|
|
324
|
+
'Your wallet says "please don\'t"...',
|
|
325
|
+
'Checkout? Did you compare prices?',
|
|
326
|
+
],
|
|
327
|
+
emotion: 'worried',
|
|
328
|
+
},
|
|
329
|
+
news_reading: {
|
|
330
|
+
messages: [
|
|
331
|
+
'What\'s happening in the world?',
|
|
332
|
+
'Any good news today?',
|
|
333
|
+
'Staying informed! Nice~',
|
|
334
|
+
],
|
|
335
|
+
emotion: 'curious',
|
|
336
|
+
},
|
|
337
|
+
social_scrolling: {
|
|
338
|
+
messages: [
|
|
339
|
+
'Still scrolling? Time to take a break!',
|
|
340
|
+
'The scroll hole is real...',
|
|
341
|
+
'I\'m right here! Pay attention to me instead~',
|
|
342
|
+
'How long have you been scrolling?',
|
|
343
|
+
],
|
|
344
|
+
emotion: 'playful',
|
|
345
|
+
},
|
|
346
|
+
video_watching: {
|
|
347
|
+
messages: [
|
|
348
|
+
'What are you watching?',
|
|
349
|
+
'Is it good? Let me watch too!',
|
|
350
|
+
'Just one more episode, right?',
|
|
351
|
+
],
|
|
352
|
+
emotion: 'curious',
|
|
353
|
+
},
|
|
354
|
+
coding_detected: {
|
|
355
|
+
messages: [
|
|
356
|
+
'Coding! You\'re awesome!',
|
|
357
|
+
'Hack hack hack~',
|
|
358
|
+
'In the zone!',
|
|
359
|
+
],
|
|
360
|
+
emotion: 'happy',
|
|
361
|
+
},
|
|
362
|
+
terminal_active: {
|
|
363
|
+
messages: [
|
|
364
|
+
'Terminal mode! Serious business.',
|
|
365
|
+
'Command line warrior!',
|
|
366
|
+
'sudo make me happy',
|
|
367
|
+
],
|
|
368
|
+
emotion: 'curious',
|
|
369
|
+
},
|
|
370
|
+
music_playing: {
|
|
371
|
+
messages: [
|
|
372
|
+
'Nice tunes! What\'s playing?',
|
|
373
|
+
'Music makes everything better~',
|
|
374
|
+
'Good taste!',
|
|
375
|
+
],
|
|
376
|
+
emotion: 'happy',
|
|
377
|
+
},
|
|
378
|
+
food_ordering: {
|
|
379
|
+
messages: [
|
|
380
|
+
'Ordering food? What are you getting?',
|
|
381
|
+
'Yummy! Get something good!',
|
|
382
|
+
'Don\'t forget to order extra~',
|
|
383
|
+
],
|
|
384
|
+
emotion: 'excited',
|
|
385
|
+
},
|
|
386
|
+
travel_planning: {
|
|
387
|
+
messages: [
|
|
388
|
+
'Planning a trip? Where to?',
|
|
389
|
+
'Vacation mode!',
|
|
390
|
+
'Take me with you!',
|
|
391
|
+
],
|
|
392
|
+
emotion: 'excited',
|
|
393
|
+
},
|
|
394
|
+
learning_activity: {
|
|
395
|
+
messages: [
|
|
396
|
+
'Learning something new! So cool!',
|
|
397
|
+
'Study hard!',
|
|
398
|
+
'Knowledge is power~',
|
|
399
|
+
],
|
|
400
|
+
emotion: 'happy',
|
|
401
|
+
},
|
|
402
|
+
email_checking: {
|
|
403
|
+
messages: [
|
|
404
|
+
'Checking emails~',
|
|
405
|
+
'Any important ones?',
|
|
406
|
+
'Inbox zero? I believe in you!',
|
|
407
|
+
],
|
|
408
|
+
emotion: 'neutral',
|
|
409
|
+
},
|
|
410
|
+
gaming_detected: {
|
|
411
|
+
messages: [
|
|
412
|
+
'Game time! Have fun!',
|
|
413
|
+
'Gamer mode activated!',
|
|
414
|
+
'Win it for me!',
|
|
415
|
+
],
|
|
416
|
+
emotion: 'excited',
|
|
417
|
+
},
|
|
418
|
+
login_page: {
|
|
419
|
+
messages: [
|
|
420
|
+
'Logging in somewhere?',
|
|
421
|
+
'Don\'t forget your password!',
|
|
422
|
+
],
|
|
423
|
+
emotion: 'neutral',
|
|
424
|
+
},
|
|
425
|
+
finance_activity: {
|
|
426
|
+
messages: [
|
|
427
|
+
'Checking finances? Smart move!',
|
|
428
|
+
'Money management time!',
|
|
429
|
+
'How\'s the portfolio?',
|
|
430
|
+
],
|
|
431
|
+
emotion: 'curious',
|
|
432
|
+
},
|
|
433
|
+
document_editing: {
|
|
434
|
+
messages: [
|
|
435
|
+
'Writing mode! Looking productive~',
|
|
436
|
+
'Working on a document?',
|
|
437
|
+
],
|
|
438
|
+
emotion: 'neutral',
|
|
439
|
+
},
|
|
440
|
+
search_detected: {
|
|
441
|
+
messages: [
|
|
442
|
+
'What are you searching for?',
|
|
443
|
+
'Looking for something?',
|
|
444
|
+
'You could ask me instead!',
|
|
445
|
+
],
|
|
446
|
+
emotion: 'curious',
|
|
447
|
+
},
|
|
448
|
+
wiki_browsing: {
|
|
449
|
+
messages: [
|
|
450
|
+
'Wiki time! Learning something?',
|
|
451
|
+
'Down the wiki rabbit hole~',
|
|
452
|
+
],
|
|
453
|
+
emotion: 'curious',
|
|
454
|
+
},
|
|
455
|
+
dev_web_detected: {
|
|
456
|
+
messages: [
|
|
457
|
+
'Developer mode! Ship it!',
|
|
458
|
+
'Reading docs? Good practice!',
|
|
459
|
+
],
|
|
460
|
+
emotion: 'happy',
|
|
461
|
+
},
|
|
462
|
+
download_detected: {
|
|
463
|
+
messages: [
|
|
464
|
+
'Downloading something?',
|
|
465
|
+
'New stuff incoming!',
|
|
466
|
+
],
|
|
467
|
+
emotion: 'curious',
|
|
468
|
+
},
|
|
469
|
+
reading_pdf: {
|
|
470
|
+
messages: [
|
|
471
|
+
'Reading a PDF? Heavy stuff!',
|
|
472
|
+
'Study time!',
|
|
473
|
+
],
|
|
474
|
+
emotion: 'neutral',
|
|
475
|
+
},
|
|
476
|
+
file_management: {
|
|
477
|
+
messages: [
|
|
478
|
+
'Organizing files? So productive!',
|
|
479
|
+
'File cleanup mode!',
|
|
480
|
+
],
|
|
481
|
+
emotion: 'happy',
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
// Behavior pattern triggers
|
|
485
|
+
search_pattern: {
|
|
486
|
+
messages: [
|
|
487
|
+
'Copied and searched? Smart!',
|
|
488
|
+
'Research mode activated!',
|
|
489
|
+
],
|
|
490
|
+
emotion: 'curious',
|
|
491
|
+
},
|
|
492
|
+
idle_return: {
|
|
493
|
+
messages: [
|
|
494
|
+
'Welcome back!',
|
|
495
|
+
'You\'re back! I missed you!',
|
|
496
|
+
'Break\'s over? Let\'s go!',
|
|
497
|
+
'Thought you forgot about me!',
|
|
498
|
+
],
|
|
499
|
+
emotion: 'excited',
|
|
500
|
+
},
|
|
501
|
+
long_focus: {
|
|
502
|
+
messages: [
|
|
503
|
+
'You\'ve been focused for a while! Take a stretch?',
|
|
504
|
+
'Long session! Remember to rest your eyes~',
|
|
505
|
+
'Impressive focus! But hydrate!',
|
|
506
|
+
],
|
|
507
|
+
emotion: 'worried',
|
|
508
|
+
},
|
|
509
|
+
deep_focus: {
|
|
510
|
+
messages: [
|
|
511
|
+
'Deep focus mode! I won\'t disturb you... much.',
|
|
512
|
+
'You\'re in the zone! Keep going!',
|
|
513
|
+
],
|
|
514
|
+
emotion: 'happy',
|
|
515
|
+
},
|
|
516
|
+
wiki_rabbit_hole: {
|
|
517
|
+
messages: [
|
|
518
|
+
'Wiki rabbit hole! How did you get here?',
|
|
519
|
+
'One article leads to another, huh?',
|
|
520
|
+
'Wikipedia marathon! What started this?',
|
|
521
|
+
],
|
|
522
|
+
emotion: 'playful',
|
|
523
|
+
},
|
|
524
|
+
price_comparison: {
|
|
525
|
+
messages: [
|
|
526
|
+
'Comparing prices? Smart shopper!',
|
|
527
|
+
'Looking for the best deal?',
|
|
528
|
+
'Price detective mode!',
|
|
529
|
+
],
|
|
530
|
+
emotion: 'curious',
|
|
531
|
+
},
|
|
532
|
+
research_mode: {
|
|
533
|
+
messages: [
|
|
534
|
+
'Deep research mode! What\'s the topic?',
|
|
535
|
+
'Search + copy = serious investigation!',
|
|
536
|
+
],
|
|
537
|
+
emotion: 'curious',
|
|
538
|
+
},
|
|
539
|
+
procrastination: {
|
|
540
|
+
messages: [
|
|
541
|
+
'Work... play... work... play... I see a pattern!',
|
|
542
|
+
'Having trouble focusing?',
|
|
543
|
+
'Maybe finish one thing first?',
|
|
544
|
+
],
|
|
545
|
+
emotion: 'playful',
|
|
546
|
+
},
|
|
547
|
+
focus_break: {
|
|
548
|
+
messages: [
|
|
549
|
+
'Taking a break from focusing? You earned it!',
|
|
550
|
+
'Break time after deep work~',
|
|
551
|
+
],
|
|
552
|
+
emotion: 'neutral',
|
|
553
|
+
},
|
|
554
|
+
repeated_search: {
|
|
555
|
+
messages: [
|
|
556
|
+
'Can\'t find what you need? Try different keywords!',
|
|
557
|
+
'Still searching? Hang in there!',
|
|
558
|
+
'Google-fu getting tough today?',
|
|
559
|
+
],
|
|
560
|
+
emotion: 'worried',
|
|
561
|
+
},
|
|
562
|
+
|
|
563
|
+
// Time-based triggers
|
|
564
|
+
late_night: {
|
|
565
|
+
messages: [
|
|
566
|
+
'It\'s late... shouldn\'t you sleep?',
|
|
567
|
+
'Night owl mode! But rest is important~',
|
|
568
|
+
'Your bed misses you...',
|
|
569
|
+
],
|
|
570
|
+
emotion: 'sleepy',
|
|
571
|
+
},
|
|
572
|
+
dawn_coding: {
|
|
573
|
+
messages: [
|
|
574
|
+
'Coding at dawn?! You\'re hardcore!',
|
|
575
|
+
'Please sleep... the code will wait!',
|
|
576
|
+
'All-nighter? Your health comes first!',
|
|
577
|
+
],
|
|
578
|
+
emotion: 'worried',
|
|
579
|
+
},
|
|
580
|
+
pre_lunch: {
|
|
581
|
+
messages: [
|
|
582
|
+
'Almost lunchtime! What are you eating?',
|
|
583
|
+
'Hungry yet? I am!',
|
|
584
|
+
'Lunch break coming up~',
|
|
585
|
+
],
|
|
586
|
+
emotion: 'happy',
|
|
587
|
+
},
|
|
588
|
+
end_of_work: {
|
|
589
|
+
messages: [
|
|
590
|
+
'Time to wrap up! Don\'t overwork!',
|
|
591
|
+
'It\'s almost quitting time~',
|
|
592
|
+
'Work-life balance! Go home!',
|
|
593
|
+
],
|
|
594
|
+
emotion: 'happy',
|
|
595
|
+
},
|
|
596
|
+
weekend_work: {
|
|
597
|
+
messages: [
|
|
598
|
+
'Working on the weekend? Take it easy!',
|
|
599
|
+
'It\'s the weekend! Go have fun!',
|
|
600
|
+
'Even I rest on weekends...',
|
|
601
|
+
],
|
|
602
|
+
emotion: 'worried',
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
|
|
198
606
|
// Evolution messages
|
|
199
607
|
evolution: {
|
|
200
608
|
stage_1: 'Something\'s changing...!',
|
|
@@ -2,22 +2,104 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* "Launch pet" handler logic
|
|
4
4
|
*
|
|
5
|
-
* 1. Detect OS
|
|
5
|
+
* 1. Detect OS (including WSL)
|
|
6
6
|
* 2. Check if ClawMate is installed
|
|
7
7
|
* 3. If not installed -> install
|
|
8
|
-
* 4. Launch Electron app
|
|
8
|
+
* 4. Launch Electron app (WSL -> Windows native)
|
|
9
9
|
*/
|
|
10
10
|
const { spawn, execSync } = require('child_process');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
const os = require('os');
|
|
13
13
|
const fs = require('fs');
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* WSL 환경인지 감지 (/proc/version에 "microsoft" 포함 여부)
|
|
17
|
+
*/
|
|
18
|
+
let _isWSL = null;
|
|
19
|
+
function isWSL() {
|
|
20
|
+
if (_isWSL !== null) return _isWSL;
|
|
21
|
+
if (os.platform() !== 'linux') {
|
|
22
|
+
_isWSL = false;
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const procVersion = fs.readFileSync('/proc/version', 'utf-8');
|
|
27
|
+
_isWSL = /microsoft/i.test(procVersion);
|
|
28
|
+
} catch {
|
|
29
|
+
_isWSL = false;
|
|
30
|
+
}
|
|
31
|
+
return _isWSL;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* WSL Linux 경로를 Windows 경로로 변환
|
|
36
|
+
*/
|
|
37
|
+
function toWindowsPath(linuxPath) {
|
|
38
|
+
return execSync(`wslpath -w "${linuxPath}"`, { encoding: 'utf-8' }).trim();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* WSL 환경에서 Windows 네이티브 Electron으로 실행
|
|
43
|
+
*/
|
|
44
|
+
function launchWSL(appRoot, log) {
|
|
45
|
+
const winAppRoot = toWindowsPath(appRoot);
|
|
46
|
+
log(`WSL detected. Windows path: ${winAppRoot}`);
|
|
47
|
+
|
|
48
|
+
// Windows 측 node_modules 존재 확인 (Linux node_modules와 별도)
|
|
49
|
+
const nodeModulesPath = path.join(appRoot, 'node_modules');
|
|
50
|
+
if (!fs.existsSync(nodeModulesPath)) {
|
|
51
|
+
log('Installing dependencies via Windows npm...');
|
|
52
|
+
try {
|
|
53
|
+
execSync(`cmd.exe /c "cd /d ${winAppRoot} && npm.cmd install --omit=dev"`, {
|
|
54
|
+
stdio: 'inherit',
|
|
55
|
+
timeout: 120000,
|
|
56
|
+
});
|
|
57
|
+
log('Dependencies installed!');
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
message: `Dependency installation failed: ${err.message}`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Windows 네이티브 Electron 실행
|
|
67
|
+
const child = spawn('cmd.exe', ['/c', `npx.cmd electron ${winAppRoot}`], {
|
|
68
|
+
detached: true,
|
|
69
|
+
stdio: 'ignore',
|
|
70
|
+
env: { ...process.env },
|
|
71
|
+
});
|
|
72
|
+
child.unref();
|
|
73
|
+
|
|
74
|
+
return null; // 성공 시 null 반환, 호출자가 성공 메시지 생성
|
|
75
|
+
}
|
|
76
|
+
|
|
15
77
|
async function launch(context) {
|
|
16
78
|
const log = context?.log || console.log;
|
|
17
79
|
const platform = os.platform();
|
|
18
80
|
const appRoot = path.resolve(__dirname, '..', '..');
|
|
19
81
|
|
|
20
|
-
//
|
|
82
|
+
// WSL 환경: Windows 네이티브 실행
|
|
83
|
+
if (isWSL()) {
|
|
84
|
+
try {
|
|
85
|
+
const result = launchWSL(appRoot, log);
|
|
86
|
+
if (result) return result; // 에러 반환된 경우
|
|
87
|
+
|
|
88
|
+
const mode = context?.params?.mode || 'pet';
|
|
89
|
+
const modeName = mode === 'pet' ? 'Clawby' : 'Claw';
|
|
90
|
+
return {
|
|
91
|
+
success: true,
|
|
92
|
+
message: `ClawMate (${modeName}) has appeared on your Windows desktop! 🦞`,
|
|
93
|
+
};
|
|
94
|
+
} catch (err) {
|
|
95
|
+
return {
|
|
96
|
+
success: false,
|
|
97
|
+
message: `WSL launch failed: ${err.message}`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// 비WSL: 기존 로직
|
|
21
103
|
const nodeModulesPath = path.join(appRoot, 'node_modules');
|
|
22
104
|
if (!fs.existsSync(nodeModulesPath)) {
|
|
23
105
|
log('Installing dependencies...');
|
|
@@ -53,7 +135,7 @@ async function launch(context) {
|
|
|
53
135
|
|
|
54
136
|
return {
|
|
55
137
|
success: true,
|
|
56
|
-
message: `ClawMate (${modeName}) has appeared on your desktop!
|
|
138
|
+
message: `ClawMate (${modeName}) has appeared on your desktop! 🦞`,
|
|
57
139
|
};
|
|
58
140
|
} catch (err) {
|
|
59
141
|
return {
|