@pheem49/mint 1.2.4 → 1.4.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.
@@ -0,0 +1,88 @@
1
+ const { exec } = require('child_process');
2
+ const { screen } = require('electron');
3
+
4
+ /**
5
+ * GranularAutomation handles low-level OS input via xdotool.
6
+ * It uses a normalized coordinate system (0-1000).
7
+ */
8
+ class GranularAutomation {
9
+ constructor() {
10
+ this.screenWidth = 1920; // Default fallback
11
+ this.screenHeight = 1080;
12
+ this.updateScreenSize();
13
+ }
14
+
15
+ updateScreenSize() {
16
+ try {
17
+ // In Electron main process, we can use the screen module
18
+ const primaryDisplay = screen.getPrimaryDisplay();
19
+ if (primaryDisplay && primaryDisplay.size) {
20
+ this.screenWidth = primaryDisplay.size.width;
21
+ this.screenHeight = primaryDisplay.size.height;
22
+ console.log(`[Automation] Screen detected: ${this.screenWidth}x${this.screenHeight}`);
23
+ }
24
+ } catch (e) {
25
+ // Fallback for CLI or cases where screen module is unavailable
26
+ exec('xdpyinfo | grep dimensions', (err, stdout) => {
27
+ if (!err && stdout) {
28
+ const match = stdout.match(/(\d+)x(\d+) pixels/);
29
+ if (match) {
30
+ this.screenWidth = parseInt(match[1]);
31
+ this.screenHeight = parseInt(match[2]);
32
+ console.log(`[Automation] Screen detected via xdpyinfo: ${this.screenWidth}x${this.screenHeight}`);
33
+ }
34
+ }
35
+ });
36
+ }
37
+ }
38
+
39
+ scaleX(x) {
40
+ return Math.round((x / 1000) * this.screenWidth);
41
+ }
42
+
43
+ scaleY(y) {
44
+ return Math.round((y / 1000) * this.screenHeight);
45
+ }
46
+
47
+ run(command) {
48
+ return new Promise((resolve, reject) => {
49
+ exec(command, (err, stdout, stderr) => {
50
+ if (err) {
51
+ console.error(`[Automation] xdotool error: ${stderr}`);
52
+ reject(err);
53
+ } else {
54
+ resolve(stdout);
55
+ }
56
+ });
57
+ });
58
+ }
59
+
60
+ async mouseMove(x, y) {
61
+ const sx = this.scaleX(x);
62
+ const sy = this.scaleY(y);
63
+ console.log(`[Automation] Moving mouse to ${sx}, ${sy}`);
64
+ return this.run(`xdotool mousemove ${sx} ${sy}`);
65
+ }
66
+
67
+ async mouseClick(x, y, button = 1) {
68
+ const sx = this.scaleX(x);
69
+ const sy = this.scaleY(y);
70
+ console.log(`[Automation] Clicking ${button} at ${sx}, ${sy}`);
71
+ // move first then click to be safe
72
+ return this.run(`xdotool mousemove ${sx} ${sy} click ${button}`);
73
+ }
74
+
75
+ async typeText(text) {
76
+ console.log(`[Automation] Typing: ${text}`);
77
+ // Escape double quotes for shell
78
+ const escaped = text.replace(/"/g, '\\"');
79
+ return this.run(`xdotool type "${escaped}"`);
80
+ }
81
+
82
+ async keyTap(key) {
83
+ console.log(`[Automation] Key tap: ${key}`);
84
+ return this.run(`xdotool key "${key}"`);
85
+ }
86
+ }
87
+
88
+ module.exports = new GranularAutomation();
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Mint Notification System
3
+ * ------------------------
4
+ * Sends system-level notifications to the user.
5
+ * Supports Linux (notify-send) as a primary target for CLI.
6
+ */
7
+
8
+ const { exec } = require('child_process');
9
+
10
+ function sendNotification(title, message, urgency = 'normal') {
11
+ // Attempt to use notify-send (Linux)
12
+ const cmd = `notify-send -u ${urgency} "${title}" "${message}"`;
13
+ exec(cmd, (err) => {
14
+ if (err) {
15
+ // Fallback: Silent console log if no notifier found
16
+ console.log(`[Notification] ${title}: ${message}`);
17
+ }
18
+ });
19
+ }
20
+
21
+ module.exports = {
22
+ sendNotification
23
+ };
@@ -38,74 +38,138 @@
38
38
  <div class="settings-content" id="settings-content">
39
39
 
40
40
  <div class="tab-pane active" id="sect-general">
41
- <!-- API Key -->
42
- <section class="setting-section">
43
- <h2 class="section-title">🔑 Gemini API Key</h2>
44
- <div class="setting-row">
45
- <label for="api-key-input">API Key</label>
46
- <div class="input-group">
47
- <input type="password" id="api-key-input" placeholder="Enter your Gemini API Key..."
48
- autocomplete="off">
49
- <button class="toggle-visibility" id="toggle-key" title="Show/Hide">👁</button>
50
- </div>
51
- <div class="api-actions">
52
- <button class="api-save-btn" id="save-api-key">Save API Key</button>
53
- <span class="api-save-status" id="api-save-status" aria-live="polite"></span>
54
- </div>
55
- <p class="hint">Get your API Key at <a href="#" id="ai-studio-link">Google AI Studio</a></p>
56
- </div>
57
- <div class="setting-row" style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; padding: 12px; background: rgba(139, 92, 246, 0.1); border-radius: 12px; border: 1px solid rgba(139, 92, 246, 0.2);">
58
- <div style="display: flex; flex-direction: column; gap: 4px;">
59
- <label for="show-desktop-widget" style="margin-bottom: 0; font-weight: 500;">Show Desktop AI Candidate</label>
60
- <span class="hint" style="font-size: 0.75rem;">Show the mini AI character on your desktop</span>
61
- </div>
62
- <label class="toggle-switch">
63
- <input type="checkbox" id="show-desktop-widget">
64
- <span class="toggle-slider"></span>
65
- </label>
66
- </div>
67
- </section>
68
- <!-- AI Provider & Model -->
69
- <section class="setting-section">
70
- <h2 class="section-title">🧠 AI Engine</h2>
71
- <div class="setting-row">
72
- <label for="ai-provider-select">Provider</label>
73
- <div class="input-group">
74
- <select id="ai-provider-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
75
- <option value="gemini" style="background: var(--bg-color)">Google Gemini (Cloud)</option>
76
- <option value="ollama" style="background: var(--bg-color)">Ollama (Local / Private)</option>
77
- </select>
78
- </div>
79
- </div>
41
+ <!-- API Keys & Hosts -->
42
+ <section class="setting-section">
43
+ <h2 class="section-title">🔑 API Keys & Hosts</h2>
44
+ <div class="setting-row">
45
+ <label for="api-key-input">Gemini API Key</label>
46
+ <div class="input-group">
47
+ <input type="password" id="api-key-input" placeholder="Enter Gemini API Key..." autocomplete="off">
48
+ <button class="toggle-visibility" onclick="const i = document.getElementById('api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
49
+ </div>
50
+ </div>
51
+ <div class="setting-row" style="margin-top: 10px;">
52
+ <label for="openai-api-key-input">OpenAI API Key</label>
53
+ <div class="input-group">
54
+ <input type="password" id="openai-api-key-input" placeholder="Enter OpenAI API Key..." autocomplete="off">
55
+ <button class="toggle-visibility" onclick="const i = document.getElementById('openai-api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
56
+ </div>
57
+ </div>
58
+ <div class="setting-row" style="margin-top: 10px;">
59
+ <label for="anthropic-api-key-input">Anthropic API Key</label>
60
+ <div class="input-group">
61
+ <input type="password" id="anthropic-api-key-input" placeholder="Enter Anthropic API Key..." autocomplete="off">
62
+ <button class="toggle-visibility" onclick="const i = document.getElementById('anthropic-api-key-input'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
63
+ </div>
64
+ </div>
65
+ <div class="setting-row" style="margin-top: 10px;">
66
+ <label for="hf-api-key">Hugging Face API Key</label>
67
+ <div class="input-group">
68
+ <input type="password" id="hf-api-key" placeholder="Enter Hugging Face API Key..." autocomplete="off">
69
+ <button class="toggle-visibility" onclick="const i = document.getElementById('hf-api-key'); i.type = i.type === 'password' ? 'text' : 'password';" title="Show/Hide">👁</button>
70
+ </div>
71
+ </div>
72
+ <div class="setting-row" style="margin-top: 10px;">
73
+ <label for="local-api-base-url">LM Studio Base URL</label>
74
+ <input type="text" id="local-api-base-url" placeholder="e.g. http://localhost:1234/v1">
75
+ </div>
76
+ <div class="setting-row" style="margin-top: 10px;">
77
+ <label for="ollama-host-input">Ollama Host</label>
78
+ <input type="text" id="ollama-host-input" placeholder="e.g. http://localhost:11434">
79
+ </div>
80
+ <div class="setting-row" style="display: flex; align-items: center; justify-content: space-between; margin-top: 20px; padding: 12px; background: rgba(139, 92, 246, 0.1); border-radius: 12px; border: 1px solid rgba(139, 92, 246, 0.2);">
81
+ <div style="display: flex; flex-direction: column; gap: 4px;">
82
+ <label for="show-desktop-widget" style="margin-bottom: 0; font-weight: 500;">Show Desktop AI Candidate</label>
83
+ <span class="hint" style="font-size: 0.75rem;">Show the mini AI character on your desktop</span>
84
+ </div>
85
+ <label class="toggle-switch">
86
+ <input type="checkbox" id="show-desktop-widget">
87
+ <span class="toggle-slider"></span>
88
+ </label>
89
+ </div>
90
+ </section>
80
91
 
81
- <!-- Gemini Options -->
82
- <div id="gemini-options" style="margin-top: 14px; padding: 12px; border: 1px solid var(--border); border-radius: 8px; background: rgba(0,0,0,0.1);">
83
- <div class="setting-row">
84
- <label for="gemini-model-select">Gemini Model</label>
85
- <div class="input-group">
86
- <select id="gemini-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
87
- <option value="gemini-2.5-flash" style="background: var(--bg-color)">gemini-2.5-flash</option>
88
- <option value="gemini-3.1-flash-lite" style="background: var(--bg-color)">gemini-3.1-flash-lite</option>
89
- <option value="gemini-3.1-flash-lite-preview" style="background: var(--bg-color)">gemini-3.1-flash-lite-preview</option>
90
- <option value="custom" style="background: var(--bg-color)">Custom...</option>
91
- </select>
92
+ <!-- Models Configuration -->
93
+ <section class="setting-section">
94
+ <h2 class="section-title">🧠 AI Engine & Default Models</h2>
95
+ <div class="setting-row">
96
+ <label for="ai-provider-select">Active Provider</label>
97
+ <div class="input-group">
98
+ <select id="ai-provider-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
99
+ <option value="gemini" style="background: var(--bg-color)">Google Gemini (Cloud)</option>
100
+ <option value="anthropic" style="background: var(--bg-color)">Anthropic Claude</option>
101
+ <option value="openai" style="background: var(--bg-color)">OpenAI</option>
102
+ <option value="ollama" style="background: var(--bg-color)">Ollama (Local / Private)</option>
103
+ <option value="huggingface" style="background: var(--bg-color)">Hugging Face (Inference API)</option>
104
+ <option value="local_openai" style="background: var(--bg-color)">Local (LM Studio / OpenAI Compatible)</option>
105
+ </select>
106
+ </div>
92
107
  </div>
93
- </div>
94
- <div class="setting-row" id="gemini-model-custom-row" style="display: none; margin-top: 10px;">
95
- <label for="gemini-model-custom">Custom Model</label>
96
- <input type="text" id="gemini-model-custom" placeholder="e.g. gemini-3.1-flash-lite-preview">
97
- </div>
98
- </div>
99
108
 
100
- <!-- Ollama Options -->
101
- <div id="ollama-options" style="display: none; margin-top: 14px; padding: 12px; border: 1px solid var(--border); border-radius: 8px; background: rgba(0,0,0,0.1);">
102
- <div class="setting-row">
103
- <label for="ollama-model-input">Ollama Model</label>
104
- <input type="text" id="ollama-model-input" placeholder="e.g. llama3:latest">
105
- <p class="hint" style="margin-top: 8px; color: #fbbf24;">Make sure Ollama is running at http://localhost:11434</p>
106
- </div>
107
- </div>
108
- </section>
109
+ <div class="setting-row" style="margin-top: 14px;">
110
+ <label for="gemini-model-select">Gemini Model</label>
111
+ <div class="input-group">
112
+ <select id="gemini-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
113
+ <option value="gemini-2.5-flash" style="background: var(--bg-color)">gemini-2.5-flash</option>
114
+ <option value="gemini-3.1-flash-lite" style="background: var(--bg-color)">gemini-3.1-flash-lite</option>
115
+ <option value="gemini-3.1-flash-lite-preview" style="background: var(--bg-color)">gemini-3.1-flash-lite-preview</option>
116
+ <option value="custom" style="background: var(--bg-color)">Custom...</option>
117
+ </select>
118
+ </div>
119
+ </div>
120
+ <div class="setting-row" id="gemini-model-custom-row" style="display: none; margin-top: 10px;">
121
+ <label for="gemini-model-custom">Custom Gemini Model</label>
122
+ <input type="text" id="gemini-model-custom" placeholder="e.g. gemini-3.1-flash-lite-preview">
123
+ </div>
124
+
125
+ <div class="setting-row" style="margin-top: 14px;">
126
+ <label for="openai-model-select">OpenAI Model</label>
127
+ <div class="input-group">
128
+ <select id="openai-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
129
+ <option value="gpt-4o" style="background: var(--bg-color)">gpt-4o</option>
130
+ <option value="gpt-4o-mini" style="background: var(--bg-color)">gpt-4o-mini</option>
131
+ <option value="o1-preview" style="background: var(--bg-color)">o1-preview</option>
132
+ <option value="o1-mini" style="background: var(--bg-color)">o1-mini</option>
133
+ <option value="custom" style="background: var(--bg-color)">Custom...</option>
134
+ </select>
135
+ </div>
136
+ </div>
137
+ <div class="setting-row" id="openai-model-custom-row" style="display: none; margin-top: 10px;">
138
+ <label for="openai-model-custom">Custom OpenAI Model</label>
139
+ <input type="text" id="openai-model-custom" placeholder="e.g. gpt-4o">
140
+ </div>
141
+
142
+ <div class="setting-row" style="margin-top: 14px;">
143
+ <label for="anthropic-model-select">Anthropic Model</label>
144
+ <div class="input-group">
145
+ <select id="anthropic-model-select" style="width: 100%; background: var(--input-bg); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; color: var(--text-main); font-family: inherit; font-size: 0.9rem; outline: none; transition: border-color 0.2s; cursor: pointer;">
146
+ <option value="claude-3-5-sonnet-latest" style="background: var(--bg-color)">claude-3-5-sonnet-latest</option>
147
+ <option value="claude-3-opus-latest" style="background: var(--bg-color)">claude-3-opus-latest</option>
148
+ <option value="claude-3-5-haiku-latest" style="background: var(--bg-color)">claude-3-5-haiku-latest</option>
149
+ <option value="custom" style="background: var(--bg-color)">Custom...</option>
150
+ </select>
151
+ </div>
152
+ </div>
153
+ <div class="setting-row" id="anthropic-model-custom-row" style="display: none; margin-top: 10px;">
154
+ <label for="anthropic-model-custom">Custom Anthropic Model</label>
155
+ <input type="text" id="anthropic-model-custom" placeholder="e.g. claude-3-5-sonnet-latest">
156
+ </div>
157
+
158
+ <div class="setting-row" style="margin-top: 14px;">
159
+ <label for="hf-model-name">Hugging Face Model</label>
160
+ <input type="text" id="hf-model-name" placeholder="e.g. meta-llama/Meta-Llama-3-8B-Instruct">
161
+ </div>
162
+
163
+ <div class="setting-row" style="margin-top: 14px;">
164
+ <label for="local-model-name">Local (LM Studio) Model</label>
165
+ <input type="text" id="local-model-name" placeholder="e.g. local-model">
166
+ </div>
167
+
168
+ <div class="setting-row" style="margin-top: 14px;">
169
+ <label for="ollama-model-input">Ollama Model</label>
170
+ <input type="text" id="ollama-model-input" placeholder="e.g. llama3:latest">
171
+ </div>
172
+ </section>
109
173
  </div>
110
174
  <div class="tab-pane" id="sect-audio">
111
175
  <!-- Audio & Voice -->
@@ -212,6 +276,20 @@
212
276
  <button class="btn-secondary" id="open-workflows-btn">Open workflows.json</button>
213
277
  <button class="btn-primary" id="reload-workflows-btn">Reload Rules</button>
214
278
  </div>
279
+ </section>
280
+ <!-- Agent Collaboration -->
281
+ <section class="setting-section">
282
+ <h2 class="section-title">🤝 Agent Collaboration</h2>
283
+ <div class="setting-row" style="display: flex; align-items: center; justify-content: space-between;">
284
+ <label for="enable-agent-collaboration" style="margin-bottom: 0;">Enable Multi-Agent Review</label>
285
+ <label class="toggle-switch">
286
+ <input type="checkbox" id="enable-agent-collaboration">
287
+ <span class="toggle-slider"></span>
288
+ </label>
289
+ </div>
290
+ <div class="setting-row" style="margin-top: 10px;">
291
+ <p class="hint">When in Code Mode, allow a secondary AI model to automatically review the code written by the primary model. (Requires multiple API keys. Costs API credits for both models.)</p>
292
+ </div>
215
293
  </section>
216
294
  </div>
217
295
  <div class="tab-pane" id="sect-theme">
@@ -352,6 +430,30 @@
352
430
  </div>
353
431
  </div>
354
432
  </section>
433
+
434
+ <!-- MCP Servers Management -->
435
+ <section class="setting-section" style="margin-top: 30px;">
436
+ <h2 class="section-title">🌐 MCP Servers (Model Context Protocol)</h2>
437
+ <p class="hint" style="margin-bottom: 16px;">Connect Mint to external tools like Google Search, GitHub, or Filesystem.</p>
438
+
439
+ <div class="mcp-list" id="mcp-server-list" style="display: flex; flex-direction: column; gap: 12px; margin-bottom: 20px;">
440
+ <!-- MCP items will be injected here -->
441
+ </div>
442
+
443
+ <div class="add-mcp-box" style="padding: 16px; background: rgba(255,255,255,0.05); border-radius: 12px; border: 1px dashed var(--border);">
444
+ <h3 style="font-size: 1rem; margin-bottom: 12px; color: var(--accent);">+ Add New MCP Server</h3>
445
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 10px;">
446
+ <input type="text" id="mcp-new-name" placeholder="Server Name (e.g. google-search)">
447
+ <input type="text" id="mcp-new-command" placeholder="Command (e.g. npx)">
448
+ </div>
449
+ <input type="text" id="mcp-new-args" placeholder="Arguments (e.g. -y @modelcontextprotocol/server-brave-search)" style="width: 100%; margin-bottom: 10px;">
450
+ <textarea id="mcp-new-env" placeholder='Env (JSON format, e.g. {"BRAVE_API_KEY": "..."})' style="width: 100%; min-height: 60px; background: var(--input-bg); color: var(--text-main); border: 1px solid var(--border); border-radius: 8px; padding: 10px; font-family: monospace; font-size: 0.8rem;"></textarea>
451
+
452
+ <button class="btn-primary" id="btn-add-mcp" style="margin-top: 10px; width: 100%;">Add MCP Server</button>
453
+ </div>
454
+
455
+ <p class="hint" style="margin-top: 12px;">Browse more servers at <a href="https://github.com/modelcontextprotocol/servers" target="_blank">MCP Servers Registry</a></p>
456
+ </section>
355
457
  </div>
356
458
  <div class="tab-pane" id="sect-shortcuts">
357
459
  <!-- Keyboard Shortcuts -->