natureco-cli 4.9.0 → 4.9.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/package.json +1 -1
- package/src/tools/calendar_add.js +94 -0
- package/src/tools/code_execution.js +86 -0
- package/src/tools/cron_create.js +105 -0
- package/src/tools/delegate_task.js +61 -0
- package/src/tools/file_search.js +85 -0
- package/src/tools/grep_search.js +127 -0
- package/src/tools/http_request.js +77 -0
- package/src/tools/kanban.js +108 -0
- package/src/tools/mac_app_open.js +38 -0
- package/src/tools/mac_app_quit.js +46 -0
- package/src/tools/mac_notify.js +50 -0
- package/src/tools/memory_search.js +112 -0
- package/src/tools/notebook_edit.js +93 -0
- package/src/tools/notes_add.js +62 -0
- package/src/tools/reminder_add.js +65 -0
- package/src/tools/shell_command.js +55 -0
- package/src/tools/text_to_speech.js +84 -98
- package/src/tools/todo_write.js +88 -0
- package/src/tools/macos.js +0 -324
|
@@ -1,105 +1,91 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* text_to_speech - TTS (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* Hermes TTS'ine benzer. Edge TTS veya OpenAI TTS.
|
|
5
|
+
* macOS'ta 'say' komutu fallback.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require("child_process");
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const os = require("os");
|
|
12
|
+
|
|
13
|
+
async function speak({ text, provider = "auto", voice = "tr-TR", savePath = null }) {
|
|
14
|
+
if (!text) return { success: false, error: "text gerekli" };
|
|
15
|
+
|
|
16
|
+
// Once dosyaya kaydet, sonra caldir
|
|
17
|
+
if (provider === "auto" || provider === "edge") {
|
|
18
|
+
return await edgeTTS(text, voice, savePath);
|
|
19
|
+
}
|
|
20
|
+
if (provider === "say") {
|
|
21
|
+
return await macSay(text);
|
|
22
|
+
}
|
|
23
|
+
if (provider === "save") {
|
|
24
|
+
return await saveToFile(text, savePath);
|
|
25
|
+
}
|
|
26
|
+
return { success: false, error: `Desteklenmeyen provider: ${provider}` };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function edgeTTS(text, voice, savePath) {
|
|
30
|
+
return new Promise((resolve) => {
|
|
31
|
+
const out = savePath || path.join(os.tmpdir(), `tts-${Date.now()}.mp3`);
|
|
32
|
+
const proc = spawn("python3", ["-c", `
|
|
33
|
+
import asyncio, sys
|
|
34
|
+
try:
|
|
35
|
+
import edge_tts
|
|
36
|
+
except ImportError:
|
|
37
|
+
print("ERROR: pip install edge-tts", file=sys.stderr)
|
|
38
|
+
sys.exit(1)
|
|
39
|
+
async def main():
|
|
40
|
+
tts = edge_tts.Communicate("""${text.replace(/"/g, "'")}""", "${voice}")
|
|
41
|
+
await tts.save("${out}")
|
|
42
|
+
asyncio.run(main())
|
|
43
|
+
`], { timeout: 30000 });
|
|
44
|
+
let stderr = "";
|
|
45
|
+
proc.stderr.on("data", d => stderr += d);
|
|
46
|
+
proc.on("close", code => {
|
|
47
|
+
if (code === 0) resolve({ success: true, provider: "edge", path: out, message: `Ses kaydedildi: ${out}` });
|
|
48
|
+
else resolve({ success: false, error: stderr || `edge-tts hata ${code}. Kur: pip install edge-tts` });
|
|
49
|
+
});
|
|
50
|
+
proc.on("error", e => resolve({ success: false, error: e.message + " (pip install edge-tts)" }));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function macSay(text) {
|
|
55
|
+
return new Promise((resolve) => {
|
|
56
|
+
const proc = spawn("say", ["-v", "Yelda", text]);
|
|
57
|
+
proc.on("close", code => {
|
|
58
|
+
if (code === 0) resolve({ success: true, provider: "mac-say", message: "Seslendirildi" });
|
|
59
|
+
else resolve({ success: false, error: `say hata ${code}` });
|
|
60
|
+
});
|
|
61
|
+
proc.on("error", e => resolve({ success: false, error: e.message }));
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function saveToFile(text, savePath) {
|
|
66
|
+
if (!savePath) return { success: false, error: "savePath gerekli" };
|
|
67
|
+
try {
|
|
68
|
+
fs.writeFileSync(savePath, text, "utf8");
|
|
69
|
+
return { success: true, provider: "save", path: savePath, message: `Metin kaydedildi: ${savePath}` };
|
|
70
|
+
} catch (e) {
|
|
71
|
+
return { success: false, error: e.message };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
2
74
|
|
|
3
75
|
module.exports = {
|
|
4
|
-
name:
|
|
5
|
-
description:
|
|
76
|
+
name: "text_to_speech",
|
|
77
|
+
description: "Metin seslendir. macOS say, edge-tts (pip install edge-tts), veya dosyaya kaydet.",
|
|
6
78
|
inputSchema: {
|
|
7
|
-
type:
|
|
79
|
+
type: "object",
|
|
8
80
|
properties: {
|
|
9
|
-
text: { type:
|
|
10
|
-
provider: { type:
|
|
11
|
-
voice: { type:
|
|
12
|
-
|
|
81
|
+
text: { type: "string", description: "Seslendirilecek metin" },
|
|
82
|
+
provider: { type: "string", description: "edge, say, save (default: auto)", enum: ["auto", "edge", "say", "save"] },
|
|
83
|
+
voice: { type: "string", description: "Ses (ornek: tr-TR-EmelNeural, en-US-AriaNeural)" },
|
|
84
|
+
savePath: { type: "string", description: "Kayıt yolu (edge/save provider için)" },
|
|
13
85
|
},
|
|
14
|
-
required: [
|
|
86
|
+
required: ["text"],
|
|
15
87
|
},
|
|
16
|
-
|
|
17
88
|
async execute(params) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const outputPath = params.outputPath;
|
|
22
|
-
|
|
23
|
-
if (provider === 'elevenlabs') {
|
|
24
|
-
const apiKey = params.apiKey || config.elevenlabsApiKey || process.env.ELEVENLABS_API_KEY;
|
|
25
|
-
if (!apiKey) {
|
|
26
|
-
return { success: false, error: 'ElevenLabs API key gerekli.\nKur: natureco config set elevenlabsApiKey <key>' };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const voice = params.voice || config.elevenlabsVoice || '21m00Tcm4TlvDq8ikWAM';
|
|
30
|
-
const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${voice}`, {
|
|
31
|
-
method: 'POST',
|
|
32
|
-
headers: { 'Content-Type': 'application/json', 'xi-api-key': apiKey },
|
|
33
|
-
body: JSON.stringify({
|
|
34
|
-
text: params.text,
|
|
35
|
-
model_id: 'eleven_monolingual_v1',
|
|
36
|
-
voice_settings: { stability: 0.5, similarity_boost: 0.5 }
|
|
37
|
-
})
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
if (!response.ok) throw new Error(`ElevenLabs error ${response.status}`);
|
|
41
|
-
|
|
42
|
-
const audioBuffer = await response.arrayBuffer();
|
|
43
|
-
if (outputPath) {
|
|
44
|
-
require('fs').writeFileSync(outputPath, Buffer.from(audioBuffer));
|
|
45
|
-
return { success: true, provider: 'elevenlabs', outputPath, size: audioBuffer.byteLength };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
success: true,
|
|
50
|
-
provider: 'elevenlabs',
|
|
51
|
-
audioData: Buffer.from(audioBuffer).toString('base64'),
|
|
52
|
-
format: 'mp3',
|
|
53
|
-
message: 'Audio generated. Use outputPath to save to file.'
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
if (provider === 'openai') {
|
|
58
|
-
const apiKey = params.apiKey || config.openaiApiKey || process.env.OPENAI_API_KEY;
|
|
59
|
-
if (!apiKey) {
|
|
60
|
-
return { success: false, error: 'OpenAI API key gerekli.' };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const voice = params.voice || 'alloy';
|
|
64
|
-
const response = await fetch('https://api.openai.com/v1/audio/speech', {
|
|
65
|
-
method: 'POST',
|
|
66
|
-
headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${apiKey}` },
|
|
67
|
-
body: JSON.stringify({ model: 'tts-1', input: params.text, voice })
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
if (!response.ok) throw new Error(`OpenAI TTS error ${response.status}`);
|
|
71
|
-
|
|
72
|
-
const audioBuffer = await response.arrayBuffer();
|
|
73
|
-
if (outputPath) {
|
|
74
|
-
require('fs').writeFileSync(outputPath, Buffer.from(audioBuffer));
|
|
75
|
-
return { success: true, provider: 'openai', outputPath, size: audioBuffer.byteLength };
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
return {
|
|
79
|
-
success: true, provider: 'openai',
|
|
80
|
-
audioData: Buffer.from(audioBuffer).toString('base64'), format: 'mp3'
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (provider === 'local') {
|
|
85
|
-
const { execSync } = require('child_process');
|
|
86
|
-
try {
|
|
87
|
-
execSync('which say || which espeak || which festival', { stdio: 'ignore' });
|
|
88
|
-
} catch {
|
|
89
|
-
return { success: false, error: 'Local TTS aracı bulunamadı. macOS: "say", Linux: "espeak"' };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const cmd = process.platform === 'darwin'
|
|
93
|
-
? `say "${params.text.replace(/"/g, '\\"')}"${outputPath ? ` -o "${outputPath}"` : ''}`
|
|
94
|
-
: `espeak "${params.text.replace(/"/g, '\\"')}"${outputPath ? ` -w "${outputPath}"` : ''}`;
|
|
95
|
-
|
|
96
|
-
execSync(cmd, { timeout: 30000 });
|
|
97
|
-
return { success: true, provider: 'local', outputPath: outputPath || 'played via speakers', message: 'Text spoken via local TTS' };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return { success: false, error: `Unknown provider: ${provider}` };
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return { success: false, error: error.message };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
};
|
|
89
|
+
return await speak(params);
|
|
90
|
+
},
|
|
91
|
+
};
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* todo_write - Yapilacaklar listesi (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* Hermes todo_write'una benzer.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
|
|
11
|
+
const TODO_FILE = path.join(os.homedir(), ".natureco", "todos.json");
|
|
12
|
+
|
|
13
|
+
function loadTodos() {
|
|
14
|
+
try {
|
|
15
|
+
if (!fs.existsSync(TODO_FILE)) return [];
|
|
16
|
+
return JSON.parse(fs.readFileSync(TODO_FILE, "utf8"));
|
|
17
|
+
} catch { return []; }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function saveTodos(todos) {
|
|
21
|
+
fs.mkdirSync(path.dirname(TODO_FILE), { recursive: true });
|
|
22
|
+
fs.writeFileSync(TODO_FILE, JSON.stringify(todos, null, 2), "utf8");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function genId() {
|
|
26
|
+
return Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function todoAction({ action = "list", content, id, priority = "medium", status }) {
|
|
30
|
+
let todos = loadTodos();
|
|
31
|
+
|
|
32
|
+
if (action === "list") {
|
|
33
|
+
const pending = todos.filter(t => t.status === "pending");
|
|
34
|
+
const done = todos.filter(t => t.status === "done");
|
|
35
|
+
return { success: true, total: todos.length, pending: pending.length, done: done.length, todos: pending };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (action === "add") {
|
|
39
|
+
if (!content) return { success: false, error: "content gerekli" };
|
|
40
|
+
const todo = { id: genId(), content, priority, status: "pending", createdAt: new Date().toISOString() };
|
|
41
|
+
todos.push(todo);
|
|
42
|
+
saveTodos(todos);
|
|
43
|
+
return { success: true, todo, message: `Todo eklendi: ${content}` };
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (action === "done") {
|
|
47
|
+
if (!id) return { success: false, error: "id gerekli" };
|
|
48
|
+
const todo = todos.find(t => t.id === id);
|
|
49
|
+
if (!todo) return { success: false, error: `Todo bulunamadi: ${id}` };
|
|
50
|
+
todo.status = "done";
|
|
51
|
+
todo.completedAt = new Date().toISOString();
|
|
52
|
+
saveTodos(todos);
|
|
53
|
+
return { success: true, todo, message: `Tamamlandi: ${todo.content}` };
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (action === "remove") {
|
|
57
|
+
if (!id) return { success: false, error: "id gerekli" };
|
|
58
|
+
const before = todos.length;
|
|
59
|
+
todos = todos.filter(t => t.id !== id);
|
|
60
|
+
saveTodos(todos);
|
|
61
|
+
return { success: true, removed: before - todos.length };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (action === "clear") {
|
|
65
|
+
saveTodos([]);
|
|
66
|
+
return { success: true, cleared: todos.length, message: "Tum todolar temizlendi" };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { success: false, error: `Bilinmeyen action: ${action}` };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
name: "todo_write",
|
|
74
|
+
description: "Yapilacaklar listesi. action: list, add, done, remove, clear.",
|
|
75
|
+
inputSchema: {
|
|
76
|
+
type: "object",
|
|
77
|
+
properties: {
|
|
78
|
+
action: { type: "string", description: "list/add/done/remove/clear (default: list)", enum: ["list", "add", "done", "remove", "clear"] },
|
|
79
|
+
content: { type: "string", description: "Todo icerigi (add icin)" },
|
|
80
|
+
id: { type: "string", description: "Todo ID (done/remove icin)" },
|
|
81
|
+
priority: { type: "string", description: "Oncelik: low/medium/high (add icin)", enum: ["low", "medium", "high"] },
|
|
82
|
+
status: { type: "string", description: "Durum filtresi: pending/done" },
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
async execute(params) {
|
|
86
|
+
return await todoAction(params);
|
|
87
|
+
},
|
|
88
|
+
};
|
package/src/tools/macos.js
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* NatureCo CLI — Calendar/Reminders/Notes Tools (v4.9.0)
|
|
3
|
-
*
|
|
4
|
-
* macOS için AppleScript entegrasyonu.
|
|
5
|
-
* Cross-platform için fallback'ler.
|
|
6
|
-
*
|
|
7
|
-
* Önemli: macOS'ta Calendar/Reminders/Notes'a erişim için
|
|
8
|
-
* "Automation" izni gerekli. Sistem Preferences → Security →
|
|
9
|
-
* Automation → natureco → Calendar/Reminders/Notes → ON
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
const { spawn } = require('child_process');
|
|
13
|
-
const os = require('os');
|
|
14
|
-
|
|
15
|
-
const IS_MAC = os.platform() === 'darwin';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* AppleScript çalıştır (macOS only)
|
|
19
|
-
*/
|
|
20
|
-
function runAppleScript(script) {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const proc = spawn('osascript', ['-e', script]);
|
|
23
|
-
let stdout = '';
|
|
24
|
-
let stderr = '';
|
|
25
|
-
proc.stdout.on('data', d => stdout += d);
|
|
26
|
-
proc.stderr.on('data', d => stderr += d);
|
|
27
|
-
proc.on('close', code => {
|
|
28
|
-
if (code === 0) resolve(stdout.trim());
|
|
29
|
-
else reject(new Error(stderr.trim() || `osascript exit ${code}`));
|
|
30
|
-
});
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Takvime etkinlik ekle (macOS Calendar)
|
|
36
|
-
* @param title - Etkinlik başlığı
|
|
37
|
-
* @param startDate - Başlangıç tarihi (ISO string veya "tomorrow 14:00")
|
|
38
|
-
* @param duration - Dakika cinsinden süre (default 60)
|
|
39
|
-
* @param calendar - Takvim adı (default: ilk takvim)
|
|
40
|
-
*/
|
|
41
|
-
async function calendarAdd({ title, startDate, duration = 60, calendar = null, notes = '', location = '' }) {
|
|
42
|
-
if (!IS_MAC) return { success: false, error: 'Calendar sadece macOS\'ta desteklenir' };
|
|
43
|
-
if (!title) return { success: false, error: 'title gerekli' };
|
|
44
|
-
|
|
45
|
-
// startDate parse — basit ISO string veya "now", "+1 hour"
|
|
46
|
-
let startScript;
|
|
47
|
-
if (startDate === 'now') startScript = 'current date';
|
|
48
|
-
else if (startDate.startsWith('+')) {
|
|
49
|
-
// "+1 hour", "+2 days"
|
|
50
|
-
const match = startDate.match(/\+(\d+)\s*(hour|day|minute)/i);
|
|
51
|
-
if (match) {
|
|
52
|
-
const n = match[1];
|
|
53
|
-
const unit = match[2].toLowerCase() + 's';
|
|
54
|
-
startScript = `(current date) + ${n} * ${unit}`;
|
|
55
|
-
} else startScript = 'current date';
|
|
56
|
-
} else {
|
|
57
|
-
startScript = `date "${startDate}"`;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Calendar adını bul
|
|
61
|
-
let calScript;
|
|
62
|
-
if (calendar) {
|
|
63
|
-
calScript = `calendar "${calendar}"`;
|
|
64
|
-
} else {
|
|
65
|
-
calScript = `first calendar whose writable is true`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const script = `
|
|
69
|
-
tell application "Calendar"
|
|
70
|
-
set targetCal to ${calScript}
|
|
71
|
-
set startDate to ${startScript}
|
|
72
|
-
set endDate to startDate + (${duration} * minutes)
|
|
73
|
-
set newEvent to make new event at end of events of targetCal with properties {summary:"${title.replace(/"/g, '\\"')}", start date:startDate, end date:endDate${location ? `, location:"${location.replace(/"/g, '\\"')}"` : ''}${notes ? `, description:"${notes.replace(/"/g, '\\"')}"` : ''}}
|
|
74
|
-
save
|
|
75
|
-
return id of newEvent
|
|
76
|
-
end tell
|
|
77
|
-
`;
|
|
78
|
-
|
|
79
|
-
try {
|
|
80
|
-
const eventId = await runAppleScript(script);
|
|
81
|
-
return {
|
|
82
|
-
success: true,
|
|
83
|
-
eventId,
|
|
84
|
-
title,
|
|
85
|
-
startDate,
|
|
86
|
-
duration,
|
|
87
|
-
message: `Takvime eklendi: "${title}" (${startDate} + ${duration}dk)`,
|
|
88
|
-
};
|
|
89
|
-
} catch (e) {
|
|
90
|
-
if (e.message.includes('-1728') || e.message.includes('not authorized') || e.message.includes('-1743')) {
|
|
91
|
-
return {
|
|
92
|
-
success: false,
|
|
93
|
-
error: 'Calendar erişim izni yok.\n\nİzin vermek için:\n1. System Preferences → Security & Privacy → Privacy → Automation\n2. natureco (veya Terminal) → Calendar → ON\n3. Tekrar dene',
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
return { success: false, error: e.message };
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Reminders'a hatırlatıcı ekle (macOS Reminders)
|
|
102
|
-
*/
|
|
103
|
-
async function reminderAdd({ title, dueDate = null, list = null, notes = '' }) {
|
|
104
|
-
if (!IS_MAC) return { success: false, error: 'Reminders sadece macOS\'ta desteklenir' };
|
|
105
|
-
if (!title) return { success: false, error: 'title gerekli' };
|
|
106
|
-
|
|
107
|
-
let listScript;
|
|
108
|
-
if (list) listScript = `list "${list}"`;
|
|
109
|
-
else listScript = `default list`;
|
|
110
|
-
|
|
111
|
-
const dueScript = dueDate
|
|
112
|
-
? (dueDate === 'today' ? 'current date' : `date "${dueDate}"`)
|
|
113
|
-
: 'missing value';
|
|
114
|
-
|
|
115
|
-
const script = `
|
|
116
|
-
tell application "Reminders"
|
|
117
|
-
set targetList to ${listScript}
|
|
118
|
-
set newReminder to make new reminder at end of targetList with properties {name:"${title.replace(/"/g, '\\"')}"${notes ? `, body:"${notes.replace(/"/g, '\\"')}"` : ''}}
|
|
119
|
-
${dueDate ? `set due date of newReminder to ${dueScript}` : ''}
|
|
120
|
-
save
|
|
121
|
-
return id of newReminder
|
|
122
|
-
end tell
|
|
123
|
-
`;
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const reminderId = await runAppleScript(script);
|
|
127
|
-
return { success: true, reminderId, title, dueDate, message: `Hatırlatıcı eklendi: "${title}"` };
|
|
128
|
-
} catch (e) {
|
|
129
|
-
if (e.message.includes('-1743') || e.message.includes('not authorized')) {
|
|
130
|
-
return {
|
|
131
|
-
success: false,
|
|
132
|
-
error: 'Reminders erişim izni yok. System Preferences → Security → Automation → Reminders → ON',
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
return { success: false, error: e.message };
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Apple Notes'a not ekle
|
|
141
|
-
*/
|
|
142
|
-
async function notesAdd({ title, content, folder = null }) {
|
|
143
|
-
if (!IS_MAC) return { success: false, error: 'Notes sadece macOS\'ta desteklenir' };
|
|
144
|
-
if (!title || !content) return { success: false, error: 'title ve content gerekli' };
|
|
145
|
-
|
|
146
|
-
const folderScript = folder ? `folder "${folder}"` : 'default folder';
|
|
147
|
-
|
|
148
|
-
// AppleScript'te yeni note oluşturma
|
|
149
|
-
const script = `
|
|
150
|
-
tell application "Notes"
|
|
151
|
-
set targetFolder to ${folderScript}
|
|
152
|
-
set newNote to make new note at targetFolder with properties {name:"${title.replace(/"/g, '\\"')}", body:"${content.replace(/"/g, '\\"').replace(/\n/g, '\\n')}"}
|
|
153
|
-
save
|
|
154
|
-
return name of newNote
|
|
155
|
-
end tell
|
|
156
|
-
`;
|
|
157
|
-
|
|
158
|
-
try {
|
|
159
|
-
const noteName = await runAppleScript(script);
|
|
160
|
-
return { success: true, noteName, title, message: `Not eklendi: "${title}"` };
|
|
161
|
-
} catch (e) {
|
|
162
|
-
if (e.message.includes('-1743') || e.message.includes('not authorized')) {
|
|
163
|
-
return {
|
|
164
|
-
success: false,
|
|
165
|
-
error: 'Notes erişim izni yok. System Preferences → Security → Automation → Notes → ON',
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
return { success: false, error: e.message };
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* macOS bildirimi göster (Notification Center)
|
|
174
|
-
*/
|
|
175
|
-
async function macNotify({ title, message, subtitle = '' }) {
|
|
176
|
-
if (!IS_MAC) return { success: false, error: 'Bildirim macOS\'a özel' };
|
|
177
|
-
if (!title || !message) return { success: false, error: 'title ve message gerekli' };
|
|
178
|
-
|
|
179
|
-
const script = `display notification "${message.replace(/"/g, '\\"')}" with title "${title.replace(/"/g, '\\"')}"${subtitle ? ` subtitle "${subtitle.replace(/"/g, '\\"')}"` : ''}`;
|
|
180
|
-
try {
|
|
181
|
-
await runAppleScript(script);
|
|
182
|
-
return { success: true, message: `Bildirim gönderildi: ${title}` };
|
|
183
|
-
} catch (e) {
|
|
184
|
-
return { success: false, error: e.message };
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* macOS uygulaması aç
|
|
190
|
-
*/
|
|
191
|
-
async function macAppOpen({ appName }) {
|
|
192
|
-
if (!IS_MAC) return { success: false, error: 'Bu komut macOS\'a özel' };
|
|
193
|
-
if (!appName) return { success: false, error: 'appName gerekli' };
|
|
194
|
-
|
|
195
|
-
return new Promise((resolve) => {
|
|
196
|
-
const proc = spawn('open', ['-a', appName]);
|
|
197
|
-
proc.on('close', (code) => {
|
|
198
|
-
if (code === 0) resolve({ success: true, message: `"${appName}" açıldı` });
|
|
199
|
-
else resolve({ success: false, error: `Uygulama açılamadı: ${appName}` });
|
|
200
|
-
});
|
|
201
|
-
proc.on('error', (e) => resolve({ success: false, error: e.message }));
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* macOS uygulaması kapat
|
|
207
|
-
*/
|
|
208
|
-
async function macAppQuit({ appName }) {
|
|
209
|
-
if (!IS_MAC) return { success: false, error: 'Bu komut macOS\'a özel' };
|
|
210
|
-
if (!appName) return { success: false, error: 'appName gerekli' };
|
|
211
|
-
|
|
212
|
-
try {
|
|
213
|
-
await runAppleScript(`tell application "${appName}" to quit`);
|
|
214
|
-
return { success: true, message: `"${appName}" kapatıldı` };
|
|
215
|
-
} catch (e) {
|
|
216
|
-
return { success: false, error: e.message };
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Tool definitions
|
|
221
|
-
module.exports = {
|
|
222
|
-
// Tek tek export (tools.js uyumlu)
|
|
223
|
-
calendar_add: {
|
|
224
|
-
name: 'calendar_add',
|
|
225
|
-
description: 'macOS Calendar\'a etkinlik ekle. "Yarın saat 14:00 toplantı ekle" gibi istekler için.',
|
|
226
|
-
inputSchema: {
|
|
227
|
-
type: 'object',
|
|
228
|
-
properties: {
|
|
229
|
-
title: { type: 'string', description: 'Etkinlik başlığı' },
|
|
230
|
-
startDate: { type: 'string', description: 'Başlangıç tarihi (ISO: 2026-06-23 14:00, veya "now", "+1 hour", "+1 day")' },
|
|
231
|
-
duration: { type: 'number', description: 'Dakika cinsinden süre (default 60)' },
|
|
232
|
-
calendar: { type: 'string', description: 'Takvim adı (default: ilk yazılabilir takvim)' },
|
|
233
|
-
notes: { type: 'string', description: 'Ek not' },
|
|
234
|
-
location: { type: 'string', description: 'Konum' },
|
|
235
|
-
},
|
|
236
|
-
required: ['title'],
|
|
237
|
-
},
|
|
238
|
-
async execute(params) {
|
|
239
|
-
return await calendarAdd(params);
|
|
240
|
-
},
|
|
241
|
-
},
|
|
242
|
-
|
|
243
|
-
reminder_add: {
|
|
244
|
-
name: 'reminder_add',
|
|
245
|
-
description: 'macOS Reminders\'a hatırlatıcı ekle. "Yarın süt al" gibi.',
|
|
246
|
-
inputSchema: {
|
|
247
|
-
type: 'object',
|
|
248
|
-
properties: {
|
|
249
|
-
title: { type: 'string', description: 'Hatırlatıcı başlığı' },
|
|
250
|
-
dueDate: { type: 'string', description: 'Son tarih (ISO string veya "today")' },
|
|
251
|
-
list: { type: 'string', description: 'Liste adı (default: default list)' },
|
|
252
|
-
notes: { type: 'string', description: 'Ek not' },
|
|
253
|
-
},
|
|
254
|
-
required: ['title'],
|
|
255
|
-
},
|
|
256
|
-
async execute(params) {
|
|
257
|
-
return await reminderAdd(params);
|
|
258
|
-
},
|
|
259
|
-
},
|
|
260
|
-
|
|
261
|
-
notes_add: {
|
|
262
|
-
name: 'notes_add',
|
|
263
|
-
description: 'Apple Notes\'a not ekle.',
|
|
264
|
-
inputSchema: {
|
|
265
|
-
type: 'object',
|
|
266
|
-
properties: {
|
|
267
|
-
title: { type: 'string', description: 'Not başlığı' },
|
|
268
|
-
content: { type: 'string', description: 'Not içeriği' },
|
|
269
|
-
folder: { type: 'string', description: 'Klasör adı (default: default folder)' },
|
|
270
|
-
},
|
|
271
|
-
required: ['title', 'content'],
|
|
272
|
-
},
|
|
273
|
-
async execute(params) {
|
|
274
|
-
return await notesAdd(params);
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
|
|
278
|
-
mac_notify: {
|
|
279
|
-
name: 'mac_notify',
|
|
280
|
-
description: 'macOS Notification Center\'da bildirim göster.',
|
|
281
|
-
inputSchema: {
|
|
282
|
-
type: 'object',
|
|
283
|
-
properties: {
|
|
284
|
-
title: { type: 'string', description: 'Bildirim başlığı' },
|
|
285
|
-
message: { type: 'string', description: 'Bildirim mesajı' },
|
|
286
|
-
subtitle: { type: 'string', description: 'Alt başlık' },
|
|
287
|
-
},
|
|
288
|
-
required: ['title', 'message'],
|
|
289
|
-
},
|
|
290
|
-
async execute(params) {
|
|
291
|
-
return await macNotify(params);
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
|
|
295
|
-
mac_app_open: {
|
|
296
|
-
name: 'mac_app_open',
|
|
297
|
-
description: 'macOS uygulaması aç (Finder, Safari, Slack, vs.).',
|
|
298
|
-
inputSchema: {
|
|
299
|
-
type: 'object',
|
|
300
|
-
properties: {
|
|
301
|
-
appName: { type: 'string', description: 'Uygulama adı (Finder, Safari, Slack, Spotify...)' },
|
|
302
|
-
},
|
|
303
|
-
required: ['appName'],
|
|
304
|
-
},
|
|
305
|
-
async execute(params) {
|
|
306
|
-
return await macAppOpen(params);
|
|
307
|
-
},
|
|
308
|
-
},
|
|
309
|
-
|
|
310
|
-
mac_app_quit: {
|
|
311
|
-
name: 'mac_app_quit',
|
|
312
|
-
description: 'macOS uygulamasını kapat.',
|
|
313
|
-
inputSchema: {
|
|
314
|
-
type: 'object',
|
|
315
|
-
properties: {
|
|
316
|
-
appName: { type: 'string', description: 'Uygulama adı' },
|
|
317
|
-
},
|
|
318
|
-
required: ['appName'],
|
|
319
|
-
},
|
|
320
|
-
async execute(params) {
|
|
321
|
-
return await macAppQuit(params);
|
|
322
|
-
},
|
|
323
|
-
},
|
|
324
|
-
};
|