@pheem49/mint 1.5.1 → 1.5.3

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 (52) hide show
  1. package/GUIDE_TH.md +7 -7
  2. package/README.md +140 -66
  3. package/assets/Agent_Mint.png +0 -0
  4. package/assets/Settings.png +0 -0
  5. package/main.js +12 -0
  6. package/mint-cli.js +148 -921
  7. package/models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json +31 -1
  8. package/models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json +6 -1
  9. package/package.json +20 -21
  10. package/preload.js +2 -0
  11. package/scripts/install_linux_desktop_entry.js +48 -0
  12. package/src/AI_Brain/Gemini_API.js +194 -491
  13. package/src/AI_Brain/autonomous_brain.js +46 -19
  14. package/src/AI_Brain/headless_agent.js +21 -2
  15. package/src/AI_Brain/proactive_engine.js +12 -2
  16. package/src/AI_Brain/provider_adapter.js +358 -0
  17. package/src/Automation_Layer/browser_automation.js +26 -24
  18. package/src/CLI/approval_handler.js +47 -0
  19. package/src/CLI/chat_router.js +7 -0
  20. package/src/CLI/chat_ui.js +586 -80
  21. package/src/CLI/cli_colors.js +115 -0
  22. package/src/CLI/cli_formatters.js +94 -0
  23. package/src/CLI/code_agent.js +825 -283
  24. package/src/CLI/intent_detectors.js +181 -0
  25. package/src/CLI/interactive_chat.js +641 -0
  26. package/src/CLI/list_features.js +3 -0
  27. package/src/CLI/repo_summarizer.js +282 -0
  28. package/src/CLI/semantic_code_search.js +312 -0
  29. package/src/CLI/skill_manager.js +41 -0
  30. package/src/CLI/slash_command_handler.js +418 -0
  31. package/src/CLI/symbol_indexer.js +231 -0
  32. package/src/CLI/updater.js +21 -1
  33. package/src/Channels/discord_bridge.js +11 -13
  34. package/src/Channels/line_bridge.js +10 -10
  35. package/src/Channels/slack_bridge.js +7 -12
  36. package/src/Channels/telegram_bridge.js +6 -14
  37. package/src/Channels/whatsapp_bridge.js +11 -9
  38. package/src/System/chat_history_manager.js +20 -12
  39. package/src/System/config_manager.js +4 -1
  40. package/src/System/ipc_handlers.js +10 -0
  41. package/src/System/optional_require.js +23 -0
  42. package/src/System/picture_store.js +109 -0
  43. package/src/System/task_manager.js +127 -0
  44. package/src/System/tool_registry.js +13 -0
  45. package/src/System/window_manager.js +16 -8
  46. package/src/UI/live2d_manager.js +246 -14
  47. package/src/UI/renderer.js +620 -45
  48. package/src/UI/settings.css +738 -439
  49. package/src/UI/settings.html +487 -432
  50. package/src/UI/settings.js +44 -10
  51. package/src/UI/styles.css +1403 -106
  52. package/privacy.txt +0 -1
@@ -9,12 +9,19 @@ function createWindowManager(projectRoot) {
9
9
  let tray = null;
10
10
 
11
11
  function createMainWindow() {
12
+ const iconPath = path.join(projectRoot, 'assets', 'icon.png');
13
+ const { width: screenWidth, height: screenHeight } = screen.getPrimaryDisplay().workAreaSize;
14
+ const windowWidth = Math.min(1360, Math.max(1180, screenWidth - 40));
15
+ const windowHeight = Math.min(920, Math.max(860, screenHeight - 40));
16
+
12
17
  mainWindow = new BrowserWindow({
13
- width: 1180,
14
- height: 860,
18
+ width: windowWidth,
19
+ height: windowHeight,
15
20
  minWidth: 900,
16
21
  minHeight: 680,
17
- icon: path.join(projectRoot, 'assets', 'icon.png'),
22
+ x: Math.floor((screenWidth - windowWidth) / 2),
23
+ y: Math.floor((screenHeight - windowHeight) / 2),
24
+ icon: nativeImage.createFromPath(iconPath),
18
25
  webPreferences: {
19
26
  preload: path.join(projectRoot, 'preload.js'),
20
27
  nodeIntegration: false,
@@ -75,12 +82,13 @@ function createWindowManager(projectRoot) {
75
82
  return settingsWindow;
76
83
  }
77
84
 
85
+ const iconPath = path.join(projectRoot, 'assets', 'icon.png');
78
86
  settingsWindow = new BrowserWindow({
79
- width: 720,
80
- height: 620,
81
- minWidth: 640,
82
- minHeight: 560,
83
- icon: path.join(projectRoot, 'assets', 'icon.png'),
87
+ width: 1020,
88
+ height: 720,
89
+ minWidth: 860,
90
+ minHeight: 620,
91
+ icon: nativeImage.createFromPath(iconPath),
84
92
  webPreferences: {
85
93
  preload: path.join(projectRoot, 'preload-settings.js'),
86
94
  nodeIntegration: false,
@@ -7,6 +7,36 @@ window.Live2DManager = {
7
7
  resizeObserver: null,
8
8
  lipSyncInterval: null,
9
9
  expIndex: 0,
10
+ interactionEnabled: true,
11
+ interactionStorageKey: 'mint-model-interaction-enabled',
12
+ accessoryStorageKey: 'mint-live2d-accessories',
13
+ activeAccessories: {},
14
+ accessoryOrder: ['glasses', 'pen', 'cat'],
15
+ accessoryParams: {
16
+ glasses: { paramId: 'Param96', label: 'Glasses' },
17
+ pen: { paramId: 'Param68', label: 'Pen' },
18
+ cat: { paramId: 'Param54', label: 'Cat Filter' }
19
+ },
20
+ pointerTrackingEnabled: true,
21
+ zoomMultiplier: 1,
22
+ interactionZoneOrigin: { x: 0.5, y: 0.58 },
23
+ fitModelToMount: null,
24
+ pointerTrackingFrame: null,
25
+ pointerTracking: {
26
+ targetX: 0,
27
+ targetY: 0,
28
+ currentX: 0,
29
+ currentY: 0,
30
+ lastMoveAt: 0
31
+ },
32
+ pointerTrackingConfig: {
33
+ focusX: 0.35,
34
+ focusY: 0.35,
35
+ rangeX: 0.35,
36
+ rangeY: 0.35,
37
+ smoothing: 0.18
38
+ },
39
+ baseModelPosition: null,
10
40
  lastInteractionAt: 0,
11
41
  expressionToastTimeout: null,
12
42
  expressionParamIds: [
@@ -39,6 +69,8 @@ window.Live2DManager = {
39
69
 
40
70
  async loadModel(mountEl, statusEl, shellEl) {
41
71
  this.statusEl = statusEl; // Store for later use
72
+ this.interactionEnabled = this.getSavedInteractionEnabled();
73
+ this.activeAccessories = this.getSavedAccessories();
42
74
  if (!mountEl) return;
43
75
  if (statusEl) {
44
76
  statusEl.classList.remove('is-error');
@@ -74,7 +106,7 @@ window.Live2DManager = {
74
106
 
75
107
  const modelUrl = new URL('../../models/Shiroko_Model/Shiroko/Shiroko_Core/%E9%9D%A2%E9%A5%BC0.model3.json', window.location.href).href;
76
108
  this.model = await window.PIXI.live2d.Live2DModel.from(modelUrl, {
77
- autoInteract: true
109
+ autoInteract: false
78
110
  });
79
111
  this.expressionToastEl = document.getElementById('expression-toast');
80
112
 
@@ -82,8 +114,9 @@ window.Live2DManager = {
82
114
  this.app.stage.addChild(this.model);
83
115
 
84
116
  // -- Interaction Setup --
85
- this.model.interactive = true;
86
- this.model.buttonMode = true;
117
+ this.setInteractionEnabled(this.interactionEnabled);
118
+ this.setupPointerTracking(mountEl);
119
+ this.applyAccessories();
87
120
 
88
121
  // Tap Interaction. This model does not define Cubism HitAreas, so use
89
122
  // normalized model coordinates to provide stable region reactions.
@@ -105,12 +138,17 @@ window.Live2DManager = {
105
138
  const heightScale = mountHeight / Math.max(modelHeight, 1);
106
139
 
107
140
  // Reduced zoom to 2.0 as requested
108
- const scale = Math.min(widthScale, heightScale) * 1.8;
141
+ const scale = Math.min(widthScale, heightScale) * 1.85 * this.zoomMultiplier;
109
142
 
110
143
  this.model.scale.set(scale);
111
144
  // Adjusted Y offset to 1.0 as requested
112
- this.model.position.set(mountWidth / 2, mountHeight / 2 + mountHeight * 0.6);
145
+ this.baseModelPosition = {
146
+ x: mountWidth / 2,
147
+ y: mountHeight / 2 + mountHeight * 0.55
148
+ };
149
+ this.applyModelFollowOffset();
113
150
  };
151
+ this.fitModelToMount = fitModel;
114
152
 
115
153
  requestAnimationFrame(() => {
116
154
  fitModel();
@@ -147,7 +185,7 @@ window.Live2DManager = {
147
185
  },
148
186
 
149
187
  handleModelTap(event) {
150
- if (!this.model) return;
188
+ if (!this.model || !this.interactionEnabled) return;
151
189
 
152
190
  const now = Date.now();
153
191
  if (now - this.lastInteractionAt < 3000) return;
@@ -180,9 +218,9 @@ window.Live2DManager = {
180
218
  try {
181
219
  const point = this.getPointerViewportPoint(event);
182
220
  if (!point) return null;
183
- const { x, y } = point;
221
+ const { x, y } = this.toInteractionZonePoint(point);
184
222
 
185
- if (this.isPointInZone(x, y, 0.37, 0.395, 0.25, 0.13)) {
223
+ if (this.isPointInZone(x, y, 0.36, 0.375, 0.28, 0.12)) {
186
224
  return {
187
225
  id: 'face',
188
226
  label: 'Cat Ears',
@@ -191,7 +229,7 @@ window.Live2DManager = {
191
229
  };
192
230
  }
193
231
 
194
- if (this.isPointInZone(x, y, 0.35, 0.30, 0.29, 0.09)) {
232
+ if (this.isPointInZone(x, y, 0.34, 0.205, 0.32, 0.155)) {
195
233
  return {
196
234
  id: 'head',
197
235
  label: 'Head Pat',
@@ -200,8 +238,8 @@ window.Live2DManager = {
200
238
  };
201
239
  }
202
240
 
203
- const isLeftHand = this.isPointInZone(x, y, 0.17, 0.65, 0.19, 0.17);
204
- const isRightHand = this.isPointInZone(x, y, 0.70, 0.67, 0.17, 0.17);
241
+ const isLeftHand = this.isPointInZone(x, y, 0.14, 0.70, 0.22, 0.16);
242
+ const isRightHand = this.isPointInZone(x, y, 0.65, 0.69, 0.23, 0.17);
205
243
  if (isLeftHand || isRightHand) {
206
244
  return {
207
245
  id: isLeftHand ? 'left-hand' : 'right-hand',
@@ -211,7 +249,7 @@ window.Live2DManager = {
211
249
  };
212
250
  }
213
251
 
214
- if (this.isPointInZone(x, y, 0.31, 0.76, 0.38, 0.24)) {
252
+ if (this.isPointInZone(x, y, 0.34, 0.74, 0.30, 0.24)) {
215
253
  return {
216
254
  id: 'lower-body',
217
255
  label: 'Careful',
@@ -220,7 +258,7 @@ window.Live2DManager = {
220
258
  };
221
259
  }
222
260
 
223
- if (this.isPointInZone(x, y, 0.36, 0.55, 0.29, 0.15)) {
261
+ if (this.isPointInZone(x, y, 0.36, 0.53, 0.29, 0.145)) {
224
262
  return {
225
263
  id: 'body',
226
264
  label: 'Shoulder Tap',
@@ -259,6 +297,17 @@ window.Live2DManager = {
259
297
  return x >= left && x <= left + width && y >= top && y <= top + height;
260
298
  },
261
299
 
300
+ toInteractionZonePoint(point) {
301
+ const scale = this.zoomMultiplier || 1;
302
+ if (Math.abs(scale - 1) < 0.001) return point;
303
+
304
+ const origin = this.interactionZoneOrigin;
305
+ return {
306
+ x: origin.x + (point.x - origin.x) / scale,
307
+ y: origin.y + (point.y - origin.y) / scale
308
+ };
309
+ },
310
+
262
311
  cycleExpression() {
263
312
  if (!this.model) return;
264
313
  this.expIndex = (this.expIndex + 1) % this.expressionNames.length;
@@ -271,6 +320,131 @@ window.Live2DManager = {
271
320
  this.showExpressionToast(`Expression: ${nextExp.label}`);
272
321
  },
273
322
 
323
+ setInteractionEnabled(isEnabled, persist = false) {
324
+ this.interactionEnabled = Boolean(isEnabled);
325
+ if (persist) {
326
+ this.saveInteractionEnabled(this.interactionEnabled);
327
+ }
328
+ if (!this.model) return;
329
+
330
+ this.model.interactive = this.interactionEnabled;
331
+ this.model.buttonMode = this.interactionEnabled;
332
+ },
333
+
334
+ setPointerTrackingEnabled(isEnabled) {
335
+ this.pointerTrackingEnabled = Boolean(isEnabled);
336
+ if (this.pointerTrackingEnabled) return;
337
+
338
+ this.resetPointerTrackingTarget();
339
+ this.pointerTracking.currentX = 0;
340
+ this.pointerTracking.currentY = 0;
341
+ this.applyModelFollowOffset();
342
+ },
343
+
344
+ setZoomMultiplier(multiplier) {
345
+ const value = Number(multiplier);
346
+ this.zoomMultiplier = this.clamp(Number.isFinite(value) ? value : 1, 0.78, 1.28);
347
+ document.documentElement.style.setProperty('--model-zone-scale', String(this.zoomMultiplier));
348
+ if (typeof this.fitModelToMount === 'function') {
349
+ this.fitModelToMount();
350
+ }
351
+ },
352
+
353
+ getSavedInteractionEnabled() {
354
+ try {
355
+ return localStorage.getItem(this.interactionStorageKey) !== 'false';
356
+ } catch (_) {
357
+ return true;
358
+ }
359
+ },
360
+
361
+ saveInteractionEnabled(isEnabled) {
362
+ try {
363
+ localStorage.setItem(this.interactionStorageKey, String(Boolean(isEnabled)));
364
+ } catch (_) {}
365
+ },
366
+
367
+ setupPointerTracking(mountEl) {
368
+ if (!mountEl) return;
369
+
370
+ window.addEventListener('mousemove', (event) => this.updatePointerTrackingTarget(event, mountEl));
371
+
372
+ if (!this.pointerTrackingFrame) {
373
+ this.pointerTrackingFrame = () => this.updatePointerTracking();
374
+ this.app?.ticker?.add(this.pointerTrackingFrame);
375
+ }
376
+ },
377
+
378
+ updatePointerTrackingTarget(event, mountEl) {
379
+ if (!this.pointerTrackingEnabled || !mountEl) return;
380
+
381
+ const rect = {
382
+ left: 0,
383
+ top: 0,
384
+ width: window.innerWidth || mountEl.getBoundingClientRect().width,
385
+ height: window.innerHeight || mountEl.getBoundingClientRect().height
386
+ };
387
+ const config = this.pointerTrackingConfig;
388
+ const centerX = rect.left + rect.width * config.focusX;
389
+ const centerY = rect.top + rect.height * config.focusY;
390
+ const rangeX = Math.max(rect.width * config.rangeX, 1);
391
+ const rangeY = Math.max(rect.height * config.rangeY, 1);
392
+
393
+ this.pointerTracking.targetX = this.clamp((event.clientX - centerX) / rangeX, -1, 1);
394
+ this.pointerTracking.targetY = this.clamp((event.clientY - centerY) / rangeY, -1, 1);
395
+ this.pointerTracking.lastMoveAt = performance.now();
396
+ },
397
+
398
+ resetPointerTrackingTarget() {
399
+ this.pointerTracking.targetX = 0;
400
+ this.pointerTracking.targetY = 0;
401
+ },
402
+
403
+ updatePointerTracking() {
404
+ if (!this.model || !this.pointerTrackingEnabled) return;
405
+
406
+ const tracking = this.pointerTracking;
407
+ const smoothing = this.pointerTrackingConfig.smoothing;
408
+ tracking.currentX += (tracking.targetX - tracking.currentX) * smoothing;
409
+ tracking.currentY += (tracking.targetY - tracking.currentY) * smoothing;
410
+
411
+ const x = tracking.currentX;
412
+ const y = tracking.currentY;
413
+ const core = this.model?.internalModel?.coreModel;
414
+ if (!core) return;
415
+
416
+ this.setLive2DParam(core, 'ParamAngleX', x * 18);
417
+ this.setLive2DParam(core, 'ParamAngleY', -y * 14);
418
+ this.setLive2DParam(core, 'ParamAngleZ', -x * 5);
419
+ this.setLive2DParam(core, 'ParamEyeBallX', x * 1.45);
420
+ this.setLive2DParam(core, 'ParamEyeBallY', -y * 1.35);
421
+ this.setLive2DParam(core, 'Param49', x * 7);
422
+ this.setLive2DParam(core, 'Param51', -y * 5);
423
+ this.setLive2DParam(core, 'Param50', -x * 3);
424
+ this.applyModelFollowOffset();
425
+ },
426
+
427
+ applyModelFollowOffset() {
428
+ if (!this.model || !this.baseModelPosition) return;
429
+
430
+ const x = this.pointerTracking.currentX || 0;
431
+ const y = this.pointerTracking.currentY || 0;
432
+ this.model.position.set(
433
+ this.baseModelPosition.x + x * 22,
434
+ this.baseModelPosition.y + y * 16
435
+ );
436
+ },
437
+
438
+ setLive2DParam(core, id, value) {
439
+ try {
440
+ core.setParameterValueById(id, value);
441
+ } catch (_) {}
442
+ },
443
+
444
+ clamp(value, min, max) {
445
+ return Math.max(min, Math.min(max, value));
446
+ },
447
+
274
448
  showExpressionToast(text, duration = 1600) {
275
449
  const toast = this.expressionToastEl || document.getElementById('expression-toast');
276
450
  if (!toast) return;
@@ -296,6 +470,7 @@ window.Live2DManager = {
296
470
 
297
471
  try {
298
472
  this.model.expression(expressionId);
473
+ requestAnimationFrame(() => this.applyAccessories());
299
474
  } catch (error) {
300
475
  console.error(`[Live2D] Failed to apply expression: ${expressionId}`, error);
301
476
  }
@@ -328,7 +503,64 @@ window.Live2DManager = {
328
503
  }
329
504
 
330
505
  this.resetExpressionParams();
331
- requestAnimationFrame(() => this.resetExpressionParams());
506
+ requestAnimationFrame(() => {
507
+ this.resetExpressionParams();
508
+ this.applyAccessories();
509
+ });
510
+ },
511
+
512
+ setAccessory(accessoryId, isEnabled, persist = false) {
513
+ if (!this.accessoryParams[accessoryId]) return;
514
+
515
+ this.activeAccessories[accessoryId] = Boolean(isEnabled);
516
+ if (persist) {
517
+ this.saveAccessories();
518
+ }
519
+ this.applyAccessory(accessoryId);
520
+ },
521
+
522
+ setExclusiveAccessory(accessoryId, persist = false) {
523
+ const nextAccessoryId = this.accessoryParams[accessoryId] ? accessoryId : null;
524
+ Object.keys(this.accessoryParams).forEach(id => {
525
+ this.activeAccessories[id] = id === nextAccessoryId;
526
+ });
527
+ if (persist) {
528
+ this.saveAccessories();
529
+ }
530
+ this.applyAccessories();
531
+ return nextAccessoryId;
532
+ },
533
+
534
+ getActiveAccessoryId() {
535
+ return this.accessoryOrder.find(id => this.activeAccessories[id]) || null;
536
+ },
537
+
538
+ applyAccessories() {
539
+ Object.keys(this.accessoryParams).forEach(accessoryId => {
540
+ this.applyAccessory(accessoryId);
541
+ });
542
+ },
543
+
544
+ applyAccessory(accessoryId) {
545
+ const accessory = this.accessoryParams[accessoryId];
546
+ const core = this.model?.internalModel?.coreModel;
547
+ if (!accessory || !core) return;
548
+
549
+ this.setLive2DParam(core, accessory.paramId, this.activeAccessories[accessoryId] ? 1 : 0);
550
+ },
551
+
552
+ getSavedAccessories() {
553
+ try {
554
+ return JSON.parse(localStorage.getItem(this.accessoryStorageKey) || '{}') || {};
555
+ } catch (_) {
556
+ return {};
557
+ }
558
+ },
559
+
560
+ saveAccessories() {
561
+ try {
562
+ localStorage.setItem(this.accessoryStorageKey, JSON.stringify(this.activeAccessories));
563
+ } catch (_) {}
332
564
  },
333
565
 
334
566
  startLipSync() {