@pheem49/mint 1.4.2 → 1.5.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/GUIDE_TH.md +113 -0
- package/README.md +267 -78
- package/assets/CLI_Screen.png +0 -0
- package/main.js +76 -890
- package/mint-cli-logic.js +3 -107
- package/mint-cli.js +594 -29
- package/models/Shiroko_Model/Shiroko/Shiroko_Core/72d86db84cfa9730b894c241fd24c0db.png +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core/items_pinned_to_model.json +14 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253/347/234/274/347/217/240/346/221/207/346/231/203.exp3.json +15 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//345/233/264/350/243/231.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/215/347/205/247.exp3.json +50 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/277/347/254/224.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//347/214/253/345/222/252/346/273/244/351/225/234.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//347/234/274/351/225/234.exp3.json +10 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_00.png +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_01.png +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_02.png +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_03.png +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.cdi3.json +1498 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.moc3 +0 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.model3.json +47 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.physics3.json +6658 -0
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.vtube.json +1299 -0
- package/models/Shiroko_Model/Shiroko//342/232/241/351/253/230/344/272/256/342/232/241/344/275/277/347/224/250/346/225/231/347/250/213/344/270/216/346/263/250/346/204/217/344/272/213/351/241/271.txt +23 -0
- package/package.json +37 -4
- package/src/AI_Brain/Gemini_API.js +223 -65
- package/src/AI_Brain/autonomous_brain.js +11 -0
- package/src/AI_Brain/behavior_memory.js +26 -5
- package/src/AI_Brain/headless_agent.js +4 -0
- package/src/AI_Brain/knowledge_base.js +61 -8
- package/src/AI_Brain/memory_store.js +354 -10
- package/src/Automation_Layer/file_operations.js +1 -1
- package/src/CLI/chat_router.js +20 -7
- package/src/CLI/chat_ui.js +596 -825
- package/src/CLI/code_agent.js +347 -56
- package/src/CLI/gmail_auth.js +210 -0
- package/src/CLI/image_input.js +90 -0
- package/src/CLI/list_features.js +2 -0
- package/src/CLI/onboarding.js +364 -55
- package/src/CLI/updater.js +210 -0
- package/src/Channels/brave_search_bridge.js +35 -0
- package/src/Channels/discord_bridge.js +68 -0
- package/src/Channels/google_search_bridge.js +38 -0
- package/src/Channels/line_bridge.js +60 -0
- package/src/Channels/slack_bridge.js +53 -0
- package/src/Channels/telegram_bridge.js +49 -0
- package/src/Channels/whatsapp_bridge.js +55 -0
- package/src/Command_Parser/parser.js +12 -1
- package/src/Plugins/gmail.js +251 -0
- package/src/Plugins/google_calendar.js +245 -19
- package/src/Plugins/notion.js +256 -0
- package/src/System/action_executor.js +178 -0
- package/src/System/bridge_manager.js +76 -0
- package/src/System/chat_history_manager.js +23 -5
- package/src/System/config_manager.js +71 -7
- package/src/System/custom_workflows.js +31 -2
- package/src/System/google_tts_urls.js +51 -0
- package/src/System/granular_automation.js +122 -53
- package/src/System/ipc_handlers.js +238 -0
- package/src/System/proactive_loop.js +153 -0
- package/src/System/safety_manager.js +273 -0
- package/src/System/sandbox_runner.js +182 -0
- package/src/System/screen_capture.js +175 -0
- package/src/System/system_automation.js +127 -81
- package/src/System/system_info.js +70 -0
- package/src/System/task_manager.js +15 -5
- package/src/System/tool_registry.js +280 -0
- package/src/System/window_manager.js +212 -0
- package/src/UI/live2d_manager.js +368 -0
- package/src/UI/renderer.js +208 -24
- package/src/UI/settings.html +24 -0
- package/src/UI/settings.js +14 -4
- package/src/UI/styles.css +466 -32
- package/.codex +0 -0
- package/docs/assets/Agent_Mint.png +0 -0
- package/docs/assets/CLI_Screen.png +0 -0
- package/docs/assets/Settings.png +0 -0
- package/docs/assets/icon.png +0 -0
- package/docs/index.html +0 -132
- package/docs/style.css +0 -579
- package/index.html +0 -16
- package/src/UI/index.html +0 -126
- package/tech_news.txt +0 -3
- package/test_knowledge.txt +0 -3
- package/tests/agent_orchestrator.test.js +0 -41
- package/tests/chat_router.test.js +0 -42
- package/tests/code_agent.test.js +0 -69
- package/tests/config_manager.test.js +0 -141
- package/tests/docker.test.js +0 -46
- package/tests/file_operations.test.js +0 -57
- package/tests/memory_store.test.js +0 -185
- package/tests/provider_routing.test.js +0 -67
- package/tests/spotify.test.js +0 -201
- package/tests/system_monitor.test.js +0 -37
- package/tests/workspace_manager.test.js +0 -56
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
const http = require('http');
|
|
2
|
+
const { execFile } = require('child_process');
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const axios = require('axios');
|
|
5
|
+
const { readConfig, writeConfig } = require('../System/config_manager');
|
|
6
|
+
|
|
7
|
+
const TOKEN_URL = 'https://oauth2.googleapis.com/token';
|
|
8
|
+
const AUTH_URL = 'https://accounts.google.com/o/oauth2/v2/auth';
|
|
9
|
+
const DEFAULT_SCOPES = [
|
|
10
|
+
'https://www.googleapis.com/auth/gmail.readonly',
|
|
11
|
+
'https://www.googleapis.com/auth/gmail.compose'
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
function buildRedirectUri(port) {
|
|
15
|
+
return `http://127.0.0.1:${port}/oauth2callback`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function buildAuthUrl({ clientId, redirectUri, state, scopes = DEFAULT_SCOPES }) {
|
|
19
|
+
const params = new URLSearchParams({
|
|
20
|
+
client_id: clientId,
|
|
21
|
+
redirect_uri: redirectUri,
|
|
22
|
+
response_type: 'code',
|
|
23
|
+
scope: scopes.join(' '),
|
|
24
|
+
access_type: 'offline',
|
|
25
|
+
prompt: 'consent',
|
|
26
|
+
state
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
return `${AUTH_URL}?${params.toString()}`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function openBrowser(url) {
|
|
33
|
+
const command = process.platform === 'darwin'
|
|
34
|
+
? 'open'
|
|
35
|
+
: process.platform === 'win32'
|
|
36
|
+
? 'cmd'
|
|
37
|
+
: 'xdg-open';
|
|
38
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url];
|
|
39
|
+
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
execFile(command, args, (error) => {
|
|
42
|
+
if (error) {
|
|
43
|
+
reject(error);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
resolve();
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function exchangeCodeForToken({ clientId, clientSecret, code, redirectUri }) {
|
|
52
|
+
const params = new URLSearchParams({
|
|
53
|
+
client_id: clientId,
|
|
54
|
+
client_secret: clientSecret,
|
|
55
|
+
code,
|
|
56
|
+
redirect_uri: redirectUri,
|
|
57
|
+
grant_type: 'authorization_code'
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const response = await axios.post(TOKEN_URL, params.toString(), {
|
|
61
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
return response.data;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function waitForOAuthCode({ port = 0, state, timeoutMs = 180000 }) {
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
let settled = false;
|
|
70
|
+
let timer = null;
|
|
71
|
+
|
|
72
|
+
const finish = (error, value) => {
|
|
73
|
+
if (settled) return;
|
|
74
|
+
settled = true;
|
|
75
|
+
if (timer) clearTimeout(timer);
|
|
76
|
+
server.close(() => {
|
|
77
|
+
if (error) reject(error);
|
|
78
|
+
else resolve(value);
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const server = http.createServer((req, res) => {
|
|
83
|
+
try {
|
|
84
|
+
const url = new URL(req.url, 'http://127.0.0.1');
|
|
85
|
+
if (url.pathname !== '/oauth2callback') {
|
|
86
|
+
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
87
|
+
res.end('Not found');
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const returnedState = url.searchParams.get('state');
|
|
92
|
+
const error = url.searchParams.get('error');
|
|
93
|
+
const code = url.searchParams.get('code');
|
|
94
|
+
|
|
95
|
+
if (error) {
|
|
96
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
97
|
+
res.end(`Gmail authorization failed: ${error}`);
|
|
98
|
+
finish(new Error(`Gmail authorization failed: ${error}`));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (!code || returnedState !== state) {
|
|
103
|
+
res.writeHead(400, { 'Content-Type': 'text/plain' });
|
|
104
|
+
res.end('Invalid Gmail authorization response.');
|
|
105
|
+
finish(new Error('Invalid Gmail authorization response.'));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
110
|
+
res.end('<h1>Gmail connected</h1><p>You can close this window and return to Mint.</p>');
|
|
111
|
+
finish(null, code);
|
|
112
|
+
} catch (err) {
|
|
113
|
+
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
114
|
+
res.end('Internal error.');
|
|
115
|
+
finish(err);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
server.on('error', finish);
|
|
120
|
+
server.listen(port, '127.0.0.1', () => {
|
|
121
|
+
timer = setTimeout(() => {
|
|
122
|
+
finish(new Error('Timed out waiting for Gmail authorization callback.'));
|
|
123
|
+
}, timeoutMs);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function runGmailAuth(options = {}) {
|
|
129
|
+
const logger = options.logger || console;
|
|
130
|
+
const config = options.readConfig ? options.readConfig() : readConfig();
|
|
131
|
+
const clientId = (config.gmailClientId || '').trim();
|
|
132
|
+
const clientSecret = (config.gmailClientSecret || '').trim();
|
|
133
|
+
const userId = (config.gmailUserId || 'me').trim() || 'me';
|
|
134
|
+
|
|
135
|
+
if (!clientId || !clientSecret) {
|
|
136
|
+
throw new Error('Missing Gmail OAuth Client ID or Client Secret. Run `mint onboard` and fill Gmail API credentials first.');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const state = crypto.randomBytes(16).toString('hex');
|
|
140
|
+
const actualPort = options.getAuthorizationCode ? Number(options.port || 8787) : await reserveLocalPort(Number(options.port || 0));
|
|
141
|
+
const redirectUri = buildRedirectUri(actualPort);
|
|
142
|
+
const codePromise = options.getAuthorizationCode
|
|
143
|
+
? null
|
|
144
|
+
: waitForOAuthCode({
|
|
145
|
+
port: actualPort,
|
|
146
|
+
state,
|
|
147
|
+
timeoutMs: options.timeoutMs || 180000
|
|
148
|
+
});
|
|
149
|
+
const authUrl = buildAuthUrl({ clientId, redirectUri, state, scopes: options.scopes || DEFAULT_SCOPES });
|
|
150
|
+
|
|
151
|
+
logger.log(`Open this Google OAuth consent link for Gmail (${userId}):\n${authUrl}\n`);
|
|
152
|
+
|
|
153
|
+
if (options.openBrowser !== false) {
|
|
154
|
+
const browserOpener = options.openBrowser || openBrowser;
|
|
155
|
+
await browserOpener(authUrl);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const code = options.getAuthorizationCode
|
|
159
|
+
? await options.getAuthorizationCode({ authUrl, state, redirectUri })
|
|
160
|
+
: await codePromise;
|
|
161
|
+
const token = await exchangeCodeForToken({
|
|
162
|
+
clientId,
|
|
163
|
+
clientSecret,
|
|
164
|
+
code,
|
|
165
|
+
redirectUri
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
if (!token.refresh_token) {
|
|
169
|
+
throw new Error('Google did not return a refresh token. Re-run `mint gmail auth`; the flow uses prompt=consent to request one.');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const nextConfig = {
|
|
173
|
+
...config,
|
|
174
|
+
gmailRefreshToken: token.refresh_token,
|
|
175
|
+
gmailUserId: userId,
|
|
176
|
+
pluginGmailEnabled: true
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const writeResult = options.writeConfig ? options.writeConfig(nextConfig) : writeConfig(nextConfig);
|
|
180
|
+
if (writeResult && writeResult.success === false) {
|
|
181
|
+
throw new Error(writeResult.message || 'Failed to save Gmail refresh token.');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
success: true,
|
|
186
|
+
userId,
|
|
187
|
+
scopes: options.scopes || DEFAULT_SCOPES
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function reserveLocalPort(port = 0) {
|
|
192
|
+
return new Promise((resolve, reject) => {
|
|
193
|
+
const server = http.createServer();
|
|
194
|
+
server.on('error', reject);
|
|
195
|
+
server.listen(port, '127.0.0.1', () => {
|
|
196
|
+
const actualPort = server.address().port;
|
|
197
|
+
server.close(() => resolve(actualPort));
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
module.exports = {
|
|
203
|
+
DEFAULT_SCOPES,
|
|
204
|
+
buildRedirectUri,
|
|
205
|
+
buildAuthUrl,
|
|
206
|
+
exchangeCodeForToken,
|
|
207
|
+
waitForOAuthCode,
|
|
208
|
+
reserveLocalPort,
|
|
209
|
+
runGmailAuth
|
|
210
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { execFileSync } = require('child_process');
|
|
4
|
+
|
|
5
|
+
const IMAGE_MIME_TYPES = {
|
|
6
|
+
'.png': 'image/png',
|
|
7
|
+
'.jpg': 'image/jpeg',
|
|
8
|
+
'.jpeg': 'image/jpeg',
|
|
9
|
+
'.webp': 'image/webp',
|
|
10
|
+
'.gif': 'image/gif'
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
function resolveImagePath(imagePath, cwd = process.cwd()) {
|
|
14
|
+
if (!imagePath || typeof imagePath !== 'string') {
|
|
15
|
+
throw new Error('Image path is required.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return path.resolve(cwd, imagePath);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function getImageMimeType(imagePath) {
|
|
22
|
+
const ext = path.extname(imagePath).toLowerCase();
|
|
23
|
+
const mimeType = IMAGE_MIME_TYPES[ext];
|
|
24
|
+
if (!mimeType) {
|
|
25
|
+
throw new Error(`Unsupported image type "${ext || '(none)'}". Supported: ${Object.keys(IMAGE_MIME_TYPES).join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
return mimeType;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function loadImageAsDataUri(imagePath, cwd = process.cwd()) {
|
|
31
|
+
const resolved = resolveImagePath(imagePath, cwd);
|
|
32
|
+
if (!fs.existsSync(resolved)) {
|
|
33
|
+
throw new Error(`Image file not found: ${imagePath}`);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const stat = fs.statSync(resolved);
|
|
37
|
+
if (!stat.isFile()) {
|
|
38
|
+
throw new Error(`Image path is not a file: ${imagePath}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const mimeType = getImageMimeType(resolved);
|
|
42
|
+
const data = fs.readFileSync(resolved).toString('base64');
|
|
43
|
+
return {
|
|
44
|
+
path: resolved,
|
|
45
|
+
mimeType,
|
|
46
|
+
dataUri: `data:${mimeType};base64,${data}`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function tryReadClipboardCommand(command, args) {
|
|
51
|
+
try {
|
|
52
|
+
return execFileSync(command, args, {
|
|
53
|
+
encoding: 'buffer',
|
|
54
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
55
|
+
stdio: ['ignore', 'pipe', 'ignore']
|
|
56
|
+
});
|
|
57
|
+
} catch (_) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function loadClipboardImageAsDataUri() {
|
|
63
|
+
const attempts = [
|
|
64
|
+
{ command: 'wl-paste', args: ['--type', 'image/png', '--no-newline'] },
|
|
65
|
+
{ command: 'xclip', args: ['-selection', 'clipboard', '-t', 'image/png', '-o'] }
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const attempt of attempts) {
|
|
69
|
+
const data = tryReadClipboardCommand(attempt.command, attempt.args);
|
|
70
|
+
if (data && data.length > 0) {
|
|
71
|
+
return {
|
|
72
|
+
path: 'clipboard',
|
|
73
|
+
mimeType: 'image/png',
|
|
74
|
+
dataUri: `data:image/png;base64,${data.toString('base64')}`
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
throw new Error('No clipboard image found. On Linux, install wl-clipboard or xclip, then copy an image and try Ctrl+V again.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
module.exports = {
|
|
83
|
+
loadImageAsDataUri,
|
|
84
|
+
loadClipboardImageAsDataUri,
|
|
85
|
+
_helpers: {
|
|
86
|
+
getImageMimeType,
|
|
87
|
+
resolveImagePath,
|
|
88
|
+
tryReadClipboardCommand
|
|
89
|
+
}
|
|
90
|
+
};
|
package/src/CLI/list_features.js
CHANGED
|
@@ -22,8 +22,10 @@ function displayFeatures() {
|
|
|
22
22
|
const commands = [
|
|
23
23
|
{ cmd: 'mint', desc: 'Start interactive chat session (Default)' },
|
|
24
24
|
{ cmd: 'mint code "<task>"', desc: 'Run workspace-aware coding agent in current directory' },
|
|
25
|
+
{ cmd: 'mint gmail auth', desc: 'Connect Gmail OAuth and save refresh token' },
|
|
25
26
|
{ cmd: 'mint mcp', desc: 'Manage Model Context Protocol (MCP) servers' },
|
|
26
27
|
{ cmd: 'mint task "<task>"', desc: 'Queue an autonomous task for the background agent' },
|
|
28
|
+
{ cmd: 'mint update', desc: 'Check for and install the latest Mint CLI version' },
|
|
27
29
|
{ cmd: 'mint onboard', desc: 'Run setup wizard (API Key, Model, Daemon)' },
|
|
28
30
|
{ cmd: 'mint agent', desc: 'Run Mint as a background agent (Headless)' },
|
|
29
31
|
{ cmd: 'mint list', desc: 'Show this features & commands list' }
|