@pheem49/mint 1.5.5 → 1.6.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/.codex +0 -0
- package/.github/FUNDING.yml +2 -0
- package/.github/workflows/ci.yml +45 -0
- package/.github/workflows/release.yml +79 -0
- package/Cargo.lock +5792 -0
- package/Cargo.toml +32 -0
- package/README.md +387 -353
- package/assets/icon.png +0 -0
- package/bin/mint +0 -0
- package/crates/mint-cli/Cargo.toml +23 -0
- package/crates/mint-cli/src/agent.rs +851 -0
- package/crates/mint-cli/src/gmail.rs +216 -0
- package/crates/mint-cli/src/image.rs +142 -0
- package/crates/mint-cli/src/main.rs +2837 -0
- package/crates/mint-cli/src/mcp.rs +63 -0
- package/crates/mint-cli/src/onboard.rs +1149 -0
- package/crates/mint-cli/src/setup.rs +390 -0
- package/crates/mint-cli/src/skills.rs +8 -0
- package/crates/mint-cli/src/updater.rs +279 -0
- package/crates/mint-core/Cargo.toml +22 -0
- package/crates/mint-core/src/agent_loop.rs +94 -0
- package/crates/mint-core/src/api_server.rs +991 -0
- package/crates/mint-core/src/channels.rs +248 -0
- package/crates/mint-core/src/chat.rs +895 -0
- package/crates/mint-core/src/code_tools.rs +729 -0
- package/crates/mint-core/src/config.rs +368 -0
- package/crates/mint-core/src/files.rs +159 -0
- package/crates/mint-core/src/knowledge.rs +541 -0
- package/crates/mint-core/src/lib.rs +84 -0
- package/crates/mint-core/src/mcp.rs +273 -0
- package/crates/mint-core/src/memory.rs +673 -0
- package/crates/mint-core/src/orchestration.rs +2157 -0
- package/crates/mint-core/src/pictures.rs +314 -0
- package/crates/mint-core/src/plugins.rs +727 -0
- package/crates/mint-core/src/safety.rs +416 -0
- package/crates/mint-core/src/semantic.rs +254 -0
- package/crates/mint-core/src/shell.rs +317 -0
- package/crates/mint-core/src/skills.rs +71 -0
- package/crates/mint-core/src/symbols.rs +157 -0
- package/crates/mint-core/src/tasks.rs +308 -0
- package/crates/mint-core/src/tts.rs +92 -0
- package/crates/mint-core/src/weather.rs +93 -0
- package/crates/mint-core/src/web_search.rs +200 -0
- package/crates/mint-core/src/workflows.rs +81 -0
- package/crates/mint-core/tests/mcp_stdio.rs +45 -0
- package/crates/mint-core/tests/memory_persistence.rs +172 -0
- package/crates/mint-core/tests/pictures_storage.rs +14 -0
- package/crates/mint-core/tests/task_lifecycle.rs +87 -0
- package/package.json +35 -99
- package/src/bin/index.js +16 -0
- package/src/renderer/index-web.html +17 -0
- package/src/renderer/index.html +17 -0
- package/src/renderer/public/Live2DCubismCore.js +9 -0
- package/src/renderer/public/assets/icon.png +0 -0
- package/src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.model3.json +36 -0
- package/src/renderer/src/App.tsx +33 -0
- package/src/renderer/src/calculator.ts +47 -0
- package/src/renderer/src/components/ChatPanel.tsx +1598 -0
- package/src/renderer/src/components/DashboardSidebar.tsx +358 -0
- package/src/renderer/src/components/Live2DStage.tsx +374 -0
- package/src/renderer/src/components/MintDashboard.tsx +950 -0
- package/src/renderer/src/components/ModelPanel.tsx +154 -0
- package/src/renderer/src/components/PicturesLibrary.tsx +46 -0
- package/src/renderer/src/components/ProactiveGlow.tsx +19 -0
- package/src/renderer/src/components/ScreenPicker.tsx +579 -0
- package/src/renderer/src/components/SettingsWindow.tsx +1467 -0
- package/src/renderer/src/components/SpotlightWindow.tsx +280 -0
- package/src/renderer/src/components/WidgetWindow.tsx +36 -0
- package/src/renderer/src/components/WorkspacePanel.tsx +268 -0
- package/src/{UI → renderer/src/css}/settings.css +69 -16
- package/src/renderer/src/css/spotlight.css +113 -0
- package/src/renderer/src/css/styles.css +3722 -0
- package/src/renderer/src/css/widget.css +185 -0
- package/src/renderer/src/env.d.ts +116 -0
- package/src/renderer/src/index.css +379 -0
- package/src/renderer/src/main.tsx +13 -0
- package/src/renderer/src/tauri.ts +996 -0
- package/src/renderer/src-web/App.tsx +25 -0
- package/src/renderer/src-web/calculator.ts +47 -0
- package/src/renderer/src-web/components/ChatPanel.tsx +1662 -0
- package/src/renderer/src-web/components/DashboardSidebar.tsx +242 -0
- package/src/renderer/src-web/components/MintDashboard.tsx +763 -0
- package/src/renderer/src-web/components/PicturesLibrary.tsx +73 -0
- package/src/renderer/src-web/components/SettingsWindow.tsx +1500 -0
- package/src/renderer/src-web/css/settings.css +1100 -0
- package/src/{UI → renderer/src-web/css}/spotlight.css +4 -4
- package/src/{UI → renderer/src-web/css}/styles.css +1055 -159
- package/src/{UI → renderer/src-web/css}/widget.css +2 -2
- package/src/renderer/src-web/env.d.ts +107 -0
- package/src/renderer/src-web/index.css +379 -0
- package/src/renderer/src-web/main.tsx +13 -0
- package/src/renderer/src-web/tauri.ts +983 -0
- package/tsconfig.json +30 -0
- package/vite.config.ts +33 -0
- package/vite.config.web.ts +51 -0
- package/GUIDE_TH.md +0 -125
- package/assets/Agent_Mint.png +0 -0
- package/assets/CLI_Screen.png +0 -0
- package/assets/Settings.png +0 -0
- package/benchmark_ai.js +0 -71
- package/install.ps1 +0 -64
- package/install.sh +0 -54
- package/main.js +0 -139
- package/mint-cli-logic.js +0 -3
- package/mint-cli.js +0 -410
- package/models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.model3.json +0 -47
- 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 +0 -23
- package/preload-picker.js +0 -11
- package/preload-settings.js +0 -11
- package/preload.js +0 -41
- package/scripts/install_linux_desktop_entry.js +0 -48
- package/src/AI_Brain/Gemini_API.js +0 -813
- package/src/AI_Brain/agent_orchestrator.js +0 -73
- package/src/AI_Brain/autonomous_brain.js +0 -179
- package/src/AI_Brain/behavior_memory.js +0 -135
- package/src/AI_Brain/headless_agent.js +0 -143
- package/src/AI_Brain/knowledge_base.js +0 -349
- package/src/AI_Brain/memory_store.js +0 -662
- package/src/AI_Brain/proactive_engine.js +0 -172
- package/src/AI_Brain/provider_adapter.js +0 -365
- package/src/Automation_Layer/browser_automation.js +0 -149
- package/src/Automation_Layer/file_operations.js +0 -286
- package/src/Automation_Layer/open_app.js +0 -85
- package/src/Automation_Layer/open_website.js +0 -38
- package/src/CLI/approval_handler.js +0 -47
- package/src/CLI/chat_router.js +0 -247
- package/src/CLI/chat_ui.js +0 -1159
- package/src/CLI/cli_colors.js +0 -115
- package/src/CLI/cli_formatters.js +0 -94
- package/src/CLI/code_agent.js +0 -1667
- package/src/CLI/code_session_memory.js +0 -62
- package/src/CLI/gmail_auth.js +0 -210
- package/src/CLI/image_input.js +0 -90
- package/src/CLI/intent_detectors.js +0 -181
- package/src/CLI/interactive_chat.js +0 -658
- package/src/CLI/list_features.js +0 -64
- package/src/CLI/onboarding.js +0 -416
- package/src/CLI/repo_summarizer.js +0 -282
- package/src/CLI/semantic_code_search.js +0 -312
- package/src/CLI/skill_manager.js +0 -41
- package/src/CLI/slash_command_handler.js +0 -418
- package/src/CLI/symbol_indexer.js +0 -231
- package/src/CLI/updater.js +0 -230
- package/src/CLI/workspace_manager.js +0 -90
- package/src/Channels/brave_search_bridge.js +0 -35
- package/src/Channels/discord_bridge.js +0 -66
- package/src/Channels/google_search_bridge.js +0 -38
- package/src/Channels/line_bridge.js +0 -60
- package/src/Channels/slack_bridge.js +0 -48
- package/src/Channels/telegram_bridge.js +0 -41
- package/src/Channels/whatsapp_bridge.js +0 -57
- package/src/Command_Parser/parser.js +0 -45
- package/src/Plugins/dev_tools.js +0 -41
- package/src/Plugins/discord.js +0 -20
- package/src/Plugins/docker.js +0 -47
- package/src/Plugins/gmail.js +0 -251
- package/src/Plugins/google_calendar.js +0 -252
- package/src/Plugins/mcp_manager.js +0 -95
- package/src/Plugins/notion.js +0 -256
- package/src/Plugins/obsidian.js +0 -54
- package/src/Plugins/plugin_manager.js +0 -81
- package/src/Plugins/spotify.js +0 -173
- package/src/Plugins/system_metrics.js +0 -31
- package/src/Plugins/system_monitor.js +0 -72
- package/src/System/action_executor.js +0 -178
- package/src/System/bridge_manager.js +0 -76
- package/src/System/chat_history_manager.js +0 -83
- package/src/System/config_manager.js +0 -194
- package/src/System/custom_workflows.js +0 -163
- package/src/System/daemon_manager.js +0 -67
- package/src/System/google_tts_urls.js +0 -51
- package/src/System/granular_automation.js +0 -157
- package/src/System/ipc_handlers.js +0 -332
- package/src/System/notifications.js +0 -23
- package/src/System/optional_require.js +0 -23
- package/src/System/picture_store.js +0 -109
- package/src/System/proactive_loop.js +0 -153
- package/src/System/safety_manager.js +0 -273
- package/src/System/sandbox_runner.js +0 -182
- package/src/System/screen_capture.js +0 -175
- package/src/System/smart_context.js +0 -227
- package/src/System/system_automation.js +0 -162
- package/src/System/system_events.js +0 -79
- package/src/System/system_info.js +0 -125
- package/src/System/task_manager.js +0 -222
- package/src/System/tool_registry.js +0 -293
- package/src/System/window_manager.js +0 -220
- package/src/UI/floating.css +0 -80
- package/src/UI/floating.html +0 -17
- package/src/UI/floating.js +0 -67
- package/src/UI/live2d_manager.js +0 -600
- package/src/UI/preload-floating.js +0 -7
- package/src/UI/preload-spotlight.js +0 -11
- package/src/UI/preload-widget.js +0 -5
- package/src/UI/proactive-glow.html +0 -42
- package/src/UI/renderer.js +0 -2127
- package/src/UI/screenPicker.html +0 -214
- package/src/UI/screenPicker.js +0 -262
- package/src/UI/settings.html +0 -577
- package/src/UI/settings.js +0 -770
- package/src/UI/spotlight.html +0 -23
- package/src/UI/spotlight.js +0 -185
- package/src/UI/widget.html +0 -29
- package/src/UI/widget.js +0 -10
- /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/72d86db84cfa9730b894c241fd24c0db.png +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/233/264/350/243/231.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/apron.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/214/253/345/222/252/346/273/244/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/catfilter.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/202/271/344/270/200/344/270/213.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/click.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//345/221/206/347/214/253.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazed.exp3.json} +0 -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" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/dazedeyes.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//347/234/274/351/225/234.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/glasses.exp3.json} +0 -0
- /package/{models → src/renderer/public/models}/Shiroko_Model/Shiroko/Shiroko_Core/items_pinned_to_model.json +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/277/347/254/224.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/pen.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//346/213/215/347/205/247.exp3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/photo.exp3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_00.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_00.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_01.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_01.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_02.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_02.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.4096/texture_03.png" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.4096/texture_03.png} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.cdi3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.cdi3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.moc3" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.moc3} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.physics3.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.physics3.json} +0 -0
- /package/{models/Shiroko_Model/Shiroko/Shiroko_Core//351/235/242/351/245/2740.vtube.json" → src/renderer/public/models/Shiroko_Model/Shiroko/Shiroko_Core/shiroko.vtube.json} +0 -0
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
const os = require('os');
|
|
2
|
-
const { getSystemInfo } = require('../System/system_info');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* System Metrics Plugin — Provides real-time hardware stats to Gemini
|
|
6
|
-
*/
|
|
7
|
-
module.exports = {
|
|
8
|
-
name: 'system_metrics',
|
|
9
|
-
description: 'Get real-time system metrics like CPU usage, RAM, and uptime. Instruction can be "all", "ram", "cpu", or "uptime".',
|
|
10
|
-
|
|
11
|
-
async execute(instruction) {
|
|
12
|
-
const info = getSystemInfo();
|
|
13
|
-
const uptimeMin = Math.floor(os.uptime() / 60);
|
|
14
|
-
const uptimeHours = (uptimeMin / 60).toFixed(1);
|
|
15
|
-
|
|
16
|
-
const inst = (instruction || 'all').toLowerCase();
|
|
17
|
-
|
|
18
|
-
if (inst.includes('ram')) {
|
|
19
|
-
return `ความจำเครื่อง (RAM): ใช้ไป ${info.ram.used} จากทั้งหมด ${info.ram.total} (${info.ram.percent})`;
|
|
20
|
-
}
|
|
21
|
-
if (inst.includes('cpu')) {
|
|
22
|
-
return `หน่วยประมวลผล (CPU): ${info.cpu.model} มีทั้งหมด ${info.cpu.cores} คอร์`;
|
|
23
|
-
}
|
|
24
|
-
if (inst.includes('uptime')) {
|
|
25
|
-
return `เปิดเครื่องมาแล้ว: ${uptimeMin} นาที (${uptimeHours} ชั่วโมง)`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Default: Return basic summary in Thai for Mint's personality
|
|
29
|
-
return `สรุปสถานะระบบ: RAM ใช้ไป ${info.ram.percent}, CPU ${info.cpu.cores} Cores, เปิดเครื่องมาแล้ว ${uptimeMin} นาทีค่ะ ✨`;
|
|
30
|
-
}
|
|
31
|
-
};
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mint System Monitor Plugin
|
|
3
|
-
* --------------------------
|
|
4
|
-
* Provides real-time system statistics for the host machine.
|
|
5
|
-
* Uses standard Linux commands (uptime, free, df) for lightweight monitoring.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { exec } = require('child_process');
|
|
9
|
-
const { promisify } = require('util');
|
|
10
|
-
const execAsync = promisify(exec);
|
|
11
|
-
const os = require('os');
|
|
12
|
-
|
|
13
|
-
async function getStats() {
|
|
14
|
-
try {
|
|
15
|
-
const [uptime, free, df] = await Promise.all([
|
|
16
|
-
execAsync('uptime -p'),
|
|
17
|
-
execAsync('free -h'),
|
|
18
|
-
execAsync('df -h / --output=pcent,avail')
|
|
19
|
-
]);
|
|
20
|
-
|
|
21
|
-
// Parse Memory
|
|
22
|
-
const memLines = free.stdout.split('\n');
|
|
23
|
-
const memLine = memLines.find(l => l.startsWith('Mem:')) || '';
|
|
24
|
-
const memParts = memLine.split(/\s+/).filter(Boolean);
|
|
25
|
-
const memUsed = memParts[2] || 'Unknown';
|
|
26
|
-
const memTotal = memParts[1] || 'Unknown';
|
|
27
|
-
|
|
28
|
-
// Parse Disk
|
|
29
|
-
const diskLines = df.stdout.trim().split('\n');
|
|
30
|
-
const diskLine = diskLines[1] || '';
|
|
31
|
-
const [diskPercent, diskAvail] = diskLine.trim().split(/\s+/);
|
|
32
|
-
|
|
33
|
-
const cpuLoad = os.loadavg()[0].toFixed(2);
|
|
34
|
-
const cpuCores = os.cpus().length;
|
|
35
|
-
|
|
36
|
-
let report = `📊 **System Health Report**\n`;
|
|
37
|
-
report += `⏱️ **Uptime:** ${uptime.stdout.trim()}\n`;
|
|
38
|
-
report += `💻 **CPU Load:** ${cpuLoad} (on ${cpuCores} cores)\n`;
|
|
39
|
-
report += `🧠 **Memory:** ${memUsed} / ${memTotal} used\n`;
|
|
40
|
-
report += `💽 **Disk (/):** ${diskAvail} available (${diskPercent} full)`;
|
|
41
|
-
|
|
42
|
-
return report;
|
|
43
|
-
} catch (err) {
|
|
44
|
-
return `❌ Error fetching system stats: ${err.message}`;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
module.exports = {
|
|
49
|
-
name: 'system_monitor',
|
|
50
|
-
description: 'Provides system statistics like CPU load, memory usage, disk space, and uptime. Target can be "stats", "cpu", "memory", or "disk".',
|
|
51
|
-
|
|
52
|
-
async execute(target) {
|
|
53
|
-
const cmd = (target || 'stats').toLowerCase().trim();
|
|
54
|
-
|
|
55
|
-
switch (cmd) {
|
|
56
|
-
case 'stats':
|
|
57
|
-
case 'health':
|
|
58
|
-
return await getStats();
|
|
59
|
-
case 'cpu':
|
|
60
|
-
return `💻 **CPU Load (1m):** ${os.loadavg()[0].toFixed(2)}\nCores: ${os.cpus().length}\nModel: ${os.cpus()[0].model}`;
|
|
61
|
-
case 'memory':
|
|
62
|
-
case 'ram':
|
|
63
|
-
const { stdout: mem } = await execAsync('free -h');
|
|
64
|
-
return `🧠 **Memory Status:**\n\`\`\`\n${mem}\`\`\``;
|
|
65
|
-
case 'disk':
|
|
66
|
-
const { stdout: disk } = await execAsync('df -h /');
|
|
67
|
-
return `💽 **Disk Status:**\n\`\`\`\n${disk}\`\`\``;
|
|
68
|
-
default:
|
|
69
|
-
return await getStats();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
};
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
let electronClipboard = null;
|
|
2
|
-
try {
|
|
3
|
-
({ clipboard: electronClipboard } = require('electron'));
|
|
4
|
-
} catch (_) {
|
|
5
|
-
electronClipboard = {
|
|
6
|
-
writeText: () => {}
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
const { openApp } = require('../Automation_Layer/open_app');
|
|
10
|
-
const { openWebsite, openSearch } = require('../Automation_Layer/open_website');
|
|
11
|
-
const { performWebAutomation } = require('../Automation_Layer/browser_automation');
|
|
12
|
-
const { createFolder, openFile, deleteFile, findPath } = require('../Automation_Layer/file_operations');
|
|
13
|
-
const { indexFile, indexFolder } = require('../AI_Brain/knowledge_base');
|
|
14
|
-
const { getSystemInfo, getWeather } = require('./system_info');
|
|
15
|
-
const pluginManager = require('../Plugins/plugin_manager');
|
|
16
|
-
const mcpManager = require('../Plugins/mcp_manager');
|
|
17
|
-
const SystemAutomation = require('./system_automation');
|
|
18
|
-
const safetyManager = require('./safety_manager');
|
|
19
|
-
const toolRegistry = require('./tool_registry');
|
|
20
|
-
const os = require('os');
|
|
21
|
-
const path = require('path');
|
|
22
|
-
|
|
23
|
-
async function executeAction(action, options = {}) {
|
|
24
|
-
if (process.env.MINT_DEBUG === '1') {
|
|
25
|
-
console.log("Executing action:", action);
|
|
26
|
-
}
|
|
27
|
-
toolRegistry.validateToolInput(action.type, action);
|
|
28
|
-
const clipboard = options.clipboard || electronClipboard;
|
|
29
|
-
const safety = safetyManager.assertActionAllowed(action, {
|
|
30
|
-
allowApproval: options.allowApproval === true,
|
|
31
|
-
allowDangerous: options.allowDangerous === true
|
|
32
|
-
});
|
|
33
|
-
safetyManager.appendActionLog({
|
|
34
|
-
source: options.source || 'action_executor',
|
|
35
|
-
action: action.type,
|
|
36
|
-
target: action.target || action.path || '',
|
|
37
|
-
tier: safety.tier,
|
|
38
|
-
approved: options.allowApproval === true || options.allowDangerous === true || safety.tier === safetyManager.TIERS.SAFE
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
switch (action.type) {
|
|
42
|
-
case 'open_url':
|
|
43
|
-
openWebsite(action.target);
|
|
44
|
-
break;
|
|
45
|
-
case 'search':
|
|
46
|
-
openSearch(action.target);
|
|
47
|
-
break;
|
|
48
|
-
case 'open_app':
|
|
49
|
-
openApp(action.target);
|
|
50
|
-
break;
|
|
51
|
-
case 'web_automation':
|
|
52
|
-
return await performWebAutomation(action.target);
|
|
53
|
-
case 'create_folder':
|
|
54
|
-
safetyManager.assertPathCapability(action.target, 'write', {
|
|
55
|
-
defaultBase: path.join(os.homedir(), 'Desktop')
|
|
56
|
-
});
|
|
57
|
-
createFolder(action.target);
|
|
58
|
-
break;
|
|
59
|
-
case 'open_file': {
|
|
60
|
-
safetyManager.assertPathCapability(action.target, 'read');
|
|
61
|
-
const fileRes = await openFile(action.target);
|
|
62
|
-
return fileRes || `Successfully opened file: ${action.target} ✅`;
|
|
63
|
-
}
|
|
64
|
-
case 'open_folder': {
|
|
65
|
-
safetyManager.assertPathCapability(action.target, 'read');
|
|
66
|
-
const folderRes = await openFile(action.target);
|
|
67
|
-
return folderRes || `Successfully opened folder: ${action.target} ✅`;
|
|
68
|
-
}
|
|
69
|
-
case 'delete_file':
|
|
70
|
-
safetyManager.assertPathCapability(action.target, 'write');
|
|
71
|
-
await deleteFile(action.target);
|
|
72
|
-
break;
|
|
73
|
-
case 'find_path':
|
|
74
|
-
return await executeFindPath(action);
|
|
75
|
-
case 'clipboard_write':
|
|
76
|
-
clipboard.writeText(action.target);
|
|
77
|
-
break;
|
|
78
|
-
case 'learn_file':
|
|
79
|
-
safetyManager.assertPathCapability(action.target, 'read');
|
|
80
|
-
return await indexFile(action.target);
|
|
81
|
-
case 'learn_folder':
|
|
82
|
-
safetyManager.assertPathCapability(action.target, 'read');
|
|
83
|
-
return await indexFolder(action.target);
|
|
84
|
-
case 'system_info':
|
|
85
|
-
return await handleSystemInfo(action.target);
|
|
86
|
-
case 'mcp_tool': {
|
|
87
|
-
const mcpResult = await mcpManager.callTool(action.server, action.target, action.args);
|
|
88
|
-
return JSON.stringify(mcpResult.content);
|
|
89
|
-
}
|
|
90
|
-
case 'mouse_move': {
|
|
91
|
-
const granularAutomation = require('./granular_automation');
|
|
92
|
-
return await granularAutomation.mouseMove(action.x, action.y);
|
|
93
|
-
}
|
|
94
|
-
case 'mouse_click': {
|
|
95
|
-
const granularAutomation = require('./granular_automation');
|
|
96
|
-
return await granularAutomation.mouseClick(action.x, action.y, action.button || 1);
|
|
97
|
-
}
|
|
98
|
-
case 'type_text': {
|
|
99
|
-
const granularAutomation = require('./granular_automation');
|
|
100
|
-
return await granularAutomation.typeText(action.target);
|
|
101
|
-
}
|
|
102
|
-
case 'key_tap': {
|
|
103
|
-
const granularAutomation = require('./granular_automation');
|
|
104
|
-
return await granularAutomation.keyTap(action.target);
|
|
105
|
-
}
|
|
106
|
-
case 'plugin':
|
|
107
|
-
return await pluginManager.executePlugin(action.pluginName, action.target);
|
|
108
|
-
case 'system_automation':
|
|
109
|
-
return await handleSystemAutomation(action.target);
|
|
110
|
-
default:
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async function handleSystemInfo(target = '') {
|
|
116
|
-
const query = String(target || '').trim();
|
|
117
|
-
if (query) {
|
|
118
|
-
const weather = await getWeather(query);
|
|
119
|
-
return JSON.stringify({
|
|
120
|
-
type: 'weather',
|
|
121
|
-
target: query,
|
|
122
|
-
...weather
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
return JSON.stringify({
|
|
126
|
-
type: 'system_info',
|
|
127
|
-
data: getSystemInfo()
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
async function executeFindPath(action) {
|
|
132
|
-
const result = findPath(action.target, {
|
|
133
|
-
type: action.pathType,
|
|
134
|
-
maxResults: 10,
|
|
135
|
-
roots: safetyManager.getAllowedRoots('read')
|
|
136
|
-
});
|
|
137
|
-
if (!result.success) {
|
|
138
|
-
return result.message;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (action.openAfter === true) {
|
|
142
|
-
if (result.matches.length === 1) {
|
|
143
|
-
const match = result.matches[0];
|
|
144
|
-
const openResult = await openFile(match.path);
|
|
145
|
-
return openResult || `Successfully found and opened ${match.type === 'dir' ? 'folder' : 'file'}: ${match.path} ✅`;
|
|
146
|
-
}
|
|
147
|
-
return `Found multiple matches for "${action.target}". Please be more specific:\n${result.matches.map(m => `- [${m.type}] ${m.path}`).join('\n')}`;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return `Found matches for "${action.target}":\n${result.matches.map(m => `- [${m.type}] ${m.path}`).join('\n')}`;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
async function handleSystemAutomation(target) {
|
|
154
|
-
const [cmd, value] = target.split(':');
|
|
155
|
-
switch (cmd) {
|
|
156
|
-
case 'volume':
|
|
157
|
-
return await SystemAutomation.setVolume(parseInt(value));
|
|
158
|
-
case 'mute':
|
|
159
|
-
return await SystemAutomation.mute();
|
|
160
|
-
case 'brightness':
|
|
161
|
-
return await SystemAutomation.setBrightness(parseInt(value));
|
|
162
|
-
case 'sleep':
|
|
163
|
-
return await SystemAutomation.sleep();
|
|
164
|
-
case 'restart':
|
|
165
|
-
return await SystemAutomation.restart();
|
|
166
|
-
case 'shutdown':
|
|
167
|
-
return await SystemAutomation.shutdown();
|
|
168
|
-
case 'minimize_all':
|
|
169
|
-
return await SystemAutomation.minimizeAll();
|
|
170
|
-
default:
|
|
171
|
-
if (SystemAutomation[target]) {
|
|
172
|
-
return await SystemAutomation[target]();
|
|
173
|
-
}
|
|
174
|
-
throw new Error(`Unknown system automation command: ${target}`);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
module.exports = { executeAction, handleSystemAutomation, handleSystemInfo };
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
const { readConfig } = require('./config_manager');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
|
|
5
|
-
class BridgeManager {
|
|
6
|
-
constructor() {
|
|
7
|
-
this.bridges = new Map();
|
|
8
|
-
this.channelsDir = path.join(__dirname, '..', 'Channels');
|
|
9
|
-
|
|
10
|
-
if (!fs.existsSync(this.channelsDir)) {
|
|
11
|
-
fs.mkdirSync(this.channelsDir, { recursive: true });
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
async init() {
|
|
16
|
-
const config = readConfig();
|
|
17
|
-
console.log('[BridgeManager] Initializing messaging bridges...');
|
|
18
|
-
|
|
19
|
-
// Load Discord Bridge
|
|
20
|
-
if (config.enableDiscordBridge && config.discordBotToken) {
|
|
21
|
-
await this.startBridge('discord', config.discordBotToken);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// Load Telegram Bridge
|
|
25
|
-
if (config.enableTelegramBridge && config.telegramBotToken) {
|
|
26
|
-
await this.startBridge('telegram', config.telegramBotToken);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Load Slack Bridge
|
|
30
|
-
if (config.enableSlackBridge && config.slackBotToken && config.slackAppToken) {
|
|
31
|
-
await this.startBridge('slack', { botToken: config.slackBotToken, appToken: config.slackAppToken });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Load LINE Bridge
|
|
35
|
-
if (config.enableLineBridge && config.lineChannelAccessToken && config.lineChannelSecret) {
|
|
36
|
-
await this.startBridge('line', { accessToken: config.lineChannelAccessToken, secret: config.lineChannelSecret, port: config.lineWebhookPort });
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Load WhatsApp Bridge
|
|
40
|
-
if (config.enableWhatsappBridge) {
|
|
41
|
-
await this.startBridge('whatsapp', null);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async startBridge(type, credentials) {
|
|
46
|
-
try {
|
|
47
|
-
const bridgePath = path.join(this.channelsDir, `${type}_bridge.js`);
|
|
48
|
-
if (!fs.existsSync(bridgePath)) {
|
|
49
|
-
console.error(`[BridgeManager] Bridge file not found: ${bridgePath}`);
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const BridgeClass = require(bridgePath);
|
|
54
|
-
const bridge = new BridgeClass(credentials);
|
|
55
|
-
await bridge.connect();
|
|
56
|
-
this.bridges.set(type, bridge);
|
|
57
|
-
console.log(`[BridgeManager] ${type.toUpperCase()} bridge connected successfully.`);
|
|
58
|
-
} catch (err) {
|
|
59
|
-
console.error(`[BridgeManager] Failed to start ${type} bridge:`, err.message);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async shutdown() {
|
|
64
|
-
for (const [type, bridge] of this.bridges.entries()) {
|
|
65
|
-
try {
|
|
66
|
-
await bridge.disconnect();
|
|
67
|
-
console.log(`[BridgeManager] ${type.toUpperCase()} bridge disconnected.`);
|
|
68
|
-
} catch (err) {
|
|
69
|
-
console.error(`[BridgeManager] Error disconnecting ${type} bridge:`, err.message);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
this.bridges.clear();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = new BridgeManager();
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
|
|
5
|
-
let app;
|
|
6
|
-
try {
|
|
7
|
-
const electron = require('electron');
|
|
8
|
-
app = electron.app;
|
|
9
|
-
} catch (e) {
|
|
10
|
-
app = null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const CONFIG_DIR = path.join(os.homedir(), '.config', 'mint');
|
|
14
|
-
const MINT_DIR = path.join(os.homedir(), '.mint');
|
|
15
|
-
|
|
16
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
17
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const CHAT_HISTORY_PATH = path.join(CONFIG_DIR, 'mint-chat-history.json');
|
|
21
|
-
|
|
22
|
-
// Migration Logic: Consolidate from various legacy locations to ~/.config/mint/
|
|
23
|
-
if (!fs.existsSync(CHAT_HISTORY_PATH)) {
|
|
24
|
-
const electronUserData = app && app.getPath ? path.join(app.getPath('userData'), 'mint-chat-history.json') : null;
|
|
25
|
-
const legacyDotMint = path.join(MINT_DIR, 'mint-chat-history.json');
|
|
26
|
-
// Legacy: file was written to the project root (CWD) before v1.5.2
|
|
27
|
-
const legacyProjectRoot = path.join(process.cwd(), 'mint-chat-history.json');
|
|
28
|
-
|
|
29
|
-
const candidates = [
|
|
30
|
-
electronUserData,
|
|
31
|
-
legacyDotMint,
|
|
32
|
-
legacyProjectRoot
|
|
33
|
-
].filter(Boolean);
|
|
34
|
-
|
|
35
|
-
for (const candidate of candidates) {
|
|
36
|
-
if (candidate !== CHAT_HISTORY_PATH && fs.existsSync(candidate)) {
|
|
37
|
-
try {
|
|
38
|
-
fs.copyFileSync(candidate, CHAT_HISTORY_PATH);
|
|
39
|
-
console.log(`[History] Migrated chat history from ${candidate}`);
|
|
40
|
-
} catch (e) {
|
|
41
|
-
console.error('[History] Migration failed:', e);
|
|
42
|
-
}
|
|
43
|
-
break;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function readChatHistory() {
|
|
49
|
-
try {
|
|
50
|
-
if (!fs.existsSync(CHAT_HISTORY_PATH)) {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const raw = fs.readFileSync(CHAT_HISTORY_PATH, 'utf-8');
|
|
55
|
-
const parsed = JSON.parse(raw);
|
|
56
|
-
return Array.isArray(parsed) ? parsed : [];
|
|
57
|
-
} catch (err) {
|
|
58
|
-
console.error('readChatHistory error:', err);
|
|
59
|
-
return [];
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function writeChatHistory(history) {
|
|
64
|
-
try {
|
|
65
|
-
const safeHistory = Array.isArray(history) ? history : [];
|
|
66
|
-
fs.writeFileSync(CHAT_HISTORY_PATH, JSON.stringify(safeHistory, null, 2), 'utf-8');
|
|
67
|
-
return { success: true };
|
|
68
|
-
} catch (err) {
|
|
69
|
-
console.error('writeChatHistory error:', err);
|
|
70
|
-
return { success: false, message: err.message };
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function clearChatHistory() {
|
|
75
|
-
return writeChatHistory([]);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
module.exports = {
|
|
79
|
-
CHAT_HISTORY_PATH,
|
|
80
|
-
readChatHistory,
|
|
81
|
-
writeChatHistory,
|
|
82
|
-
clearChatHistory
|
|
83
|
-
};
|
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const path = require('path');
|
|
3
|
-
const os = require('os');
|
|
4
|
-
|
|
5
|
-
let app;
|
|
6
|
-
try {
|
|
7
|
-
const electron = require('electron');
|
|
8
|
-
app = electron.app;
|
|
9
|
-
} catch (e) {
|
|
10
|
-
app = null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const CONFIG_DIR = path.join(os.homedir(), '.config', 'mint');
|
|
14
|
-
const LEGACY_DIR = path.join(os.homedir(), '.mint');
|
|
15
|
-
|
|
16
|
-
if (!fs.existsSync(CONFIG_DIR)) {
|
|
17
|
-
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Migration: If old .mint exists but new .config/mint is empty, move files
|
|
21
|
-
if (fs.existsSync(LEGACY_DIR) && fs.readdirSync(CONFIG_DIR).length === 0) {
|
|
22
|
-
try {
|
|
23
|
-
const files = fs.readdirSync(LEGACY_DIR);
|
|
24
|
-
for (const file of files) {
|
|
25
|
-
fs.copyFileSync(path.join(LEGACY_DIR, file), path.join(CONFIG_DIR, file));
|
|
26
|
-
}
|
|
27
|
-
console.log('[Config] Migrated settings from ~/.mint to ~/.config/mint');
|
|
28
|
-
} catch (e) {
|
|
29
|
-
console.error('[Config] Migration failed:', e);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const CONFIG_PATH = path.join(CONFIG_DIR, 'mint-config.json');
|
|
34
|
-
|
|
35
|
-
const DEFAULT_CONFIG = {
|
|
36
|
-
theme: 'dark',
|
|
37
|
-
accentColor: '#8b5cf6',
|
|
38
|
-
systemTextColor: '#f8fafc',
|
|
39
|
-
customBgStart: '#0f172a',
|
|
40
|
-
customBgEnd: '#1e1b4b',
|
|
41
|
-
customPanelBg: '#1e293b',
|
|
42
|
-
glassBlur: 'blur(16px)',
|
|
43
|
-
fontFamily: "'Outfit', sans-serif",
|
|
44
|
-
fontSize: '15px',
|
|
45
|
-
apiKey: '',
|
|
46
|
-
geminiModel: 'gemini-2.5-flash',
|
|
47
|
-
language: 'th-TH',
|
|
48
|
-
assistantMode: 'chat',
|
|
49
|
-
automationBrowser: 'chromium',
|
|
50
|
-
proactiveInterval: 60, // seconds between screen captures
|
|
51
|
-
proactiveCooldown: 120, // seconds minimum between actual suggestions
|
|
52
|
-
aiProvider: 'gemini',
|
|
53
|
-
ollamaModel: 'llama3:latest',
|
|
54
|
-
enableVoiceReply: true,
|
|
55
|
-
enableCustomWorkflows: true,
|
|
56
|
-
ttsProvider: 'google',
|
|
57
|
-
ttsVolume: 1.0,
|
|
58
|
-
ttsSpeed: 1.0,
|
|
59
|
-
ttsPitch: 1.0,
|
|
60
|
-
pluginCalendarEnabled: false,
|
|
61
|
-
pluginGmailEnabled: false,
|
|
62
|
-
pluginNotionEnabled: false,
|
|
63
|
-
pluginDiscordEnabled: false,
|
|
64
|
-
showDesktopWidget: true,
|
|
65
|
-
mcpServers: {},
|
|
66
|
-
telegramBotToken: '',
|
|
67
|
-
enableTelegramBridge: false,
|
|
68
|
-
discordBotToken: '',
|
|
69
|
-
enableDiscordBridge: false,
|
|
70
|
-
slackBotToken: '',
|
|
71
|
-
slackAppToken: '',
|
|
72
|
-
enableSlackBridge: false,
|
|
73
|
-
lineChannelAccessToken: '',
|
|
74
|
-
lineChannelSecret: '',
|
|
75
|
-
enableLineBridge: false,
|
|
76
|
-
lineWebhookPort: 3000,
|
|
77
|
-
enableWhatsappBridge: false,
|
|
78
|
-
googleSearchApiKey: '',
|
|
79
|
-
googleSearchCx: '',
|
|
80
|
-
googleCalendarClientId: '',
|
|
81
|
-
googleCalendarClientSecret: '',
|
|
82
|
-
googleCalendarRefreshToken: '',
|
|
83
|
-
googleCalendarId: 'primary',
|
|
84
|
-
gmailClientId: '',
|
|
85
|
-
gmailClientSecret: '',
|
|
86
|
-
gmailRefreshToken: '',
|
|
87
|
-
gmailUserId: 'me',
|
|
88
|
-
notionApiKey: '',
|
|
89
|
-
notionDatabaseId: '',
|
|
90
|
-
notionPageId: '',
|
|
91
|
-
notionTitleProperty: 'Name',
|
|
92
|
-
braveSearchApiKey: '',
|
|
93
|
-
anthropicApiKey: '',
|
|
94
|
-
|
|
95
|
-
openaiApiKey: '',
|
|
96
|
-
hfApiKey: '',
|
|
97
|
-
anthropicModel: 'claude-3-5-sonnet-latest',
|
|
98
|
-
openaiModel: 'gpt-4o',
|
|
99
|
-
hfModel: 'meta-llama/Meta-Llama-3-8B-Instruct',
|
|
100
|
-
localApiBaseUrl: '',
|
|
101
|
-
localModelName: 'local-model',
|
|
102
|
-
ollamaHost: '',
|
|
103
|
-
enableAgentCollaboration: false,
|
|
104
|
-
enableAutoUpdate: true,
|
|
105
|
-
autoUpdateCheckIntervalHours: 24,
|
|
106
|
-
lastUpdateCheckAt: '',
|
|
107
|
-
safetyEnabled: true,
|
|
108
|
-
sandboxMode: 'prefer', // off | prefer | enforce
|
|
109
|
-
sandboxCommand: process.platform === 'darwin' ? 'sandbox-exec' : process.platform === 'linux' ? 'bwrap' : '',
|
|
110
|
-
allowedReadPaths: [
|
|
111
|
-
os.homedir(),
|
|
112
|
-
process.cwd(),
|
|
113
|
-
path.join(os.homedir(), 'Desktop'),
|
|
114
|
-
path.join(os.homedir(), 'Documents'),
|
|
115
|
-
path.join(os.homedir(), 'Downloads'),
|
|
116
|
-
path.join(os.homedir(), 'Pictures'),
|
|
117
|
-
path.join(os.homedir(), 'Music'),
|
|
118
|
-
path.join(os.homedir(), 'Videos')
|
|
119
|
-
],
|
|
120
|
-
allowedWritePaths: [
|
|
121
|
-
os.homedir(),
|
|
122
|
-
process.cwd(),
|
|
123
|
-
path.join(os.homedir(), 'Desktop'),
|
|
124
|
-
path.join(os.homedir(), 'Documents'),
|
|
125
|
-
path.join(os.homedir(), 'Downloads'),
|
|
126
|
-
path.join(os.homedir(), 'Pictures'),
|
|
127
|
-
path.join(os.homedir(), 'Music'),
|
|
128
|
-
path.join(os.homedir(), 'Videos')
|
|
129
|
-
],
|
|
130
|
-
blockedPaths: [
|
|
131
|
-
path.join(os.homedir(), '.ssh'),
|
|
132
|
-
path.join(os.homedir(), '.gnupg'),
|
|
133
|
-
path.join(os.homedir(), '.config', 'mint', 'mint-config.json'),
|
|
134
|
-
path.join(os.homedir(), '.mint', 'mint-config.json')
|
|
135
|
-
],
|
|
136
|
-
blockedFileNames: ['.env', 'id_rsa', 'id_ed25519']
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
function readConfig() {
|
|
142
|
-
try {
|
|
143
|
-
if (!fs.existsSync(CONFIG_PATH)) {
|
|
144
|
-
writeConfig(DEFAULT_CONFIG);
|
|
145
|
-
return DEFAULT_CONFIG;
|
|
146
|
-
}
|
|
147
|
-
const raw = fs.readFileSync(CONFIG_PATH, 'utf-8');
|
|
148
|
-
return { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
|
|
149
|
-
} catch (err) {
|
|
150
|
-
console.error('readConfig error:', err);
|
|
151
|
-
return DEFAULT_CONFIG;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function writeConfig(config) {
|
|
156
|
-
try {
|
|
157
|
-
fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
|
|
158
|
-
return { success: true };
|
|
159
|
-
} catch (err) {
|
|
160
|
-
console.error('writeConfig error:', err);
|
|
161
|
-
return { success: false, message: err.message };
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function getAvailableProviders(config) {
|
|
166
|
-
const providers = [];
|
|
167
|
-
const cfg = config || readConfig();
|
|
168
|
-
|
|
169
|
-
// Check which providers have API keys or URLs configured
|
|
170
|
-
const anthropicKey = cfg.anthropicApiKey || process.env.ANTHROPIC_API_KEY;
|
|
171
|
-
if (!isPlaceholder(anthropicKey)) providers.push('anthropic');
|
|
172
|
-
|
|
173
|
-
const openaiKey = cfg.openaiApiKey || process.env.OPENAI_API_KEY;
|
|
174
|
-
if (!isPlaceholder(openaiKey)) providers.push('openai');
|
|
175
|
-
|
|
176
|
-
const geminiKey = cfg.apiKey || process.env.GEMINI_API_KEY;
|
|
177
|
-
if (!isPlaceholder(geminiKey)) providers.push('gemini');
|
|
178
|
-
|
|
179
|
-
const hfKey = cfg.hfApiKey || process.env.HF_API_KEY;
|
|
180
|
-
if (!isPlaceholder(hfKey)) providers.push('huggingface');
|
|
181
|
-
|
|
182
|
-
if (cfg.localApiBaseUrl && cfg.localApiBaseUrl.trim() !== '') providers.push('local_openai');
|
|
183
|
-
|
|
184
|
-
// Always push ollama at the end since it's local
|
|
185
|
-
providers.push('ollama');
|
|
186
|
-
|
|
187
|
-
return providers;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
function isPlaceholder(val) {
|
|
191
|
-
return !val || val.startsWith('your_') || val.includes('key_here') || val.trim() === '';
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
module.exports = { readConfig, writeConfig, getAvailableProviders, isPlaceholder, CONFIG_PATH, CONFIG_DIR };
|