natureco-cli 4.9.0 → 5.0.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.
- package/CHANGELOG.md +486 -422
- package/package.json +1 -1
- package/src/commands/skills.js +497 -414
- 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/skills_autoload.js +97 -0
- package/src/tools/skills_marketplace.js +233 -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
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kanban - Kanban board, gorev yonetimi (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* Hermes kanban'ina benzer. Durum bazli: todo, in_progress, done.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
|
|
11
|
+
const KANBAN_FILE = path.join(os.homedir(), ".natureco", "kanban.json");
|
|
12
|
+
|
|
13
|
+
function loadBoard() {
|
|
14
|
+
try {
|
|
15
|
+
if (!fs.existsSync(KANBAN_FILE)) return { columns: { todo: [], in_progress: [], done: [] } };
|
|
16
|
+
return JSON.parse(fs.readFileSync(KANBAN_FILE, "utf8"));
|
|
17
|
+
} catch { return { columns: { todo: [], in_progress: [], done: [] } }; }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function saveBoard(board) {
|
|
21
|
+
fs.mkdirSync(path.dirname(KANBAN_FILE), { recursive: true });
|
|
22
|
+
fs.writeFileSync(KANBAN_FILE, JSON.stringify(board, null, 2), "utf8");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function genId() {
|
|
26
|
+
return "k-" + Date.now().toString(36) + Math.random().toString(36).slice(2, 5);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function kanbanOp({ action = "view", title, description = "", column = "todo", id, priority = "medium" }) {
|
|
30
|
+
let board = loadBoard();
|
|
31
|
+
|
|
32
|
+
if (action === "view" || action === "list") {
|
|
33
|
+
const summary = Object.entries(board.columns).map(([col, items]) => ({
|
|
34
|
+
column: col,
|
|
35
|
+
count: items.length,
|
|
36
|
+
items,
|
|
37
|
+
}));
|
|
38
|
+
return { success: true, summary };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (action === "add") {
|
|
42
|
+
if (!title) return { success: false, error: "title gerekli" };
|
|
43
|
+
const card = { id: genId(), title, description, priority, createdAt: new Date().toISOString() };
|
|
44
|
+
if (!board.columns[column]) board.columns[column] = [];
|
|
45
|
+
board.columns[column].push(card);
|
|
46
|
+
saveBoard(board);
|
|
47
|
+
return { success: true, card, message: `"${title}" ${column} kolonuna eklendi` };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (action === "move") {
|
|
51
|
+
if (!id) return { success: false, error: "id gerekli" };
|
|
52
|
+
let card;
|
|
53
|
+
let fromCol;
|
|
54
|
+
for (const [col, items] of Object.entries(board.columns)) {
|
|
55
|
+
const idx = items.findIndex(c => c.id === id);
|
|
56
|
+
if (idx >= 0) {
|
|
57
|
+
card = items[idx];
|
|
58
|
+
fromCol = col;
|
|
59
|
+
items.splice(idx, 1);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!card) return { success: false, error: `Kart bulunamadi: ${id}` };
|
|
64
|
+
if (!board.columns[column]) board.columns[column] = [];
|
|
65
|
+
board.columns[column].push(card);
|
|
66
|
+
saveBoard(board);
|
|
67
|
+
return { success: true, card, from: fromCol, to: column, message: `Tasindi: ${fromCol} -> ${column}` };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (action === "remove") {
|
|
71
|
+
if (!id) return { success: false, error: "id gerekli" };
|
|
72
|
+
let removed = false;
|
|
73
|
+
for (const items of Object.values(board.columns)) {
|
|
74
|
+
const idx = items.findIndex(c => c.id === id);
|
|
75
|
+
if (idx >= 0) { items.splice(idx, 1); removed = true; break; }
|
|
76
|
+
}
|
|
77
|
+
if (!removed) return { success: false, error: `Kart bulunamadi: ${id}` };
|
|
78
|
+
saveBoard(board);
|
|
79
|
+
return { success: true, message: "Kart silindi" };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (action === "clear") {
|
|
83
|
+
const cleared = Object.values(board.columns).reduce((s, c) => s + c.length, 0);
|
|
84
|
+
saveBoard({ columns: { todo: [], in_progress: [], done: [] } });
|
|
85
|
+
return { success: true, cleared, message: "Tum kartlar temizlendi" };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return { success: false, error: `Bilinmeyen action: ${action}` };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = {
|
|
92
|
+
name: "kanban",
|
|
93
|
+
description: "Kanban board: todo/in_progress/done kolonlarina kart ekle, tasi, sil. action: view/add/move/remove/clear.",
|
|
94
|
+
inputSchema: {
|
|
95
|
+
type: "object",
|
|
96
|
+
properties: {
|
|
97
|
+
action: { type: "string", description: "view/add/move/remove/clear (default: view)", enum: ["view", "add", "move", "remove", "clear"] },
|
|
98
|
+
title: { type: "string", description: "Kart basligi (add icin)" },
|
|
99
|
+
description: { type: "string", description: "Kart aciklamasi (add icin)" },
|
|
100
|
+
column: { type: "string", description: "Kolon: todo/in_progress/done (default: todo)", enum: ["todo", "in_progress", "done"] },
|
|
101
|
+
id: { type: "string", description: "Kart ID (move/remove icin)" },
|
|
102
|
+
priority: { type: "string", description: "low/medium/high (add icin)", enum: ["low", "medium", "high"] },
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
async execute(params) {
|
|
106
|
+
return await kanbanOp(params);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mac_app_open - macOS uygulamasi ac (v4.9.1)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const IS_MAC = os.platform() === "darwin";
|
|
9
|
+
|
|
10
|
+
async function macAppOpen(params) {
|
|
11
|
+
if (!IS_MAC) return { success: false, error: "macOS'a ozgu" };
|
|
12
|
+
const { appName } = params;
|
|
13
|
+
if (!appName) return { success: false, error: "appName gerekli" };
|
|
14
|
+
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
const proc = spawn("open", ["-a", appName]);
|
|
17
|
+
proc.on("close", code => {
|
|
18
|
+
if (code === 0) resolve({ success: true, message: `"${appName}" acildi` });
|
|
19
|
+
else resolve({ success: false, error: `Uygulama acilamadi: ${appName}` });
|
|
20
|
+
});
|
|
21
|
+
proc.on("error", e => resolve({ success: false, error: e.message }));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
module.exports = {
|
|
26
|
+
name: "mac_app_open",
|
|
27
|
+
description: "macOS uygulamasi ac (Finder, Safari, Slack, vs.).",
|
|
28
|
+
inputSchema: {
|
|
29
|
+
type: "object",
|
|
30
|
+
properties: {
|
|
31
|
+
appName: { type: "string", description: 'Uygulama adi (Finder, Safari, Slack, Spotify...)' },
|
|
32
|
+
},
|
|
33
|
+
required: ["appName"],
|
|
34
|
+
},
|
|
35
|
+
async execute(params) {
|
|
36
|
+
return await macAppOpen(params);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mac_app_quit - macOS uygulamasi kapat (v4.9.1)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const IS_MAC = os.platform() === "darwin";
|
|
9
|
+
|
|
10
|
+
function runAppleScript(script) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const proc = spawn("osascript", ["-e", script]);
|
|
13
|
+
let out = ""; let err = "";
|
|
14
|
+
proc.stdout.on("data", d => out += d);
|
|
15
|
+
proc.stderr.on("data", d => err += d);
|
|
16
|
+
proc.on("close", code => code === 0 ? resolve(out.trim()) : reject(new Error(err.trim())));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function macAppQuit(params) {
|
|
21
|
+
if (!IS_MAC) return { success: false, error: "macOS'a ozgu" };
|
|
22
|
+
const { appName } = params;
|
|
23
|
+
if (!appName) return { success: false, error: "appName gerekli" };
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
await runAppleScript(`tell application "${appName}" to quit`);
|
|
27
|
+
return { success: true, message: `"${appName}" kapatildi` };
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return { success: false, error: e.message };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
module.exports = {
|
|
34
|
+
name: "mac_app_quit",
|
|
35
|
+
description: "macOS uygulamasi kapat.",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
appName: { type: "string", description: "Uygulama adi" },
|
|
40
|
+
},
|
|
41
|
+
required: ["appName"],
|
|
42
|
+
},
|
|
43
|
+
async execute(params) {
|
|
44
|
+
return await macAppQuit(params);
|
|
45
|
+
},
|
|
46
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mac_notify - macOS bildirim goster (v4.9.1)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const IS_MAC = os.platform() === "darwin";
|
|
9
|
+
|
|
10
|
+
function runAppleScript(script) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const proc = spawn("osascript", ["-e", script]);
|
|
13
|
+
let out = ""; let err = "";
|
|
14
|
+
proc.stdout.on("data", d => out += d);
|
|
15
|
+
proc.stderr.on("data", d => err += d);
|
|
16
|
+
proc.on("close", code => code === 0 ? resolve(out.trim()) : reject(new Error(err.trim())));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function macNotify(params) {
|
|
21
|
+
if (!IS_MAC) return { success: false, error: "macOS'a ozgu" };
|
|
22
|
+
const { title, message, subtitle = "" } = params;
|
|
23
|
+
if (!title || !message) return { success: false, error: "title ve message gerekli" };
|
|
24
|
+
|
|
25
|
+
const script = `display notification "${message.replace(/"/g, "'")}" with title "${title.replace(/"/g, "'")}"${subtitle ? ` subtitle "${subtitle.replace(/"/g, "'")}"` : ""}`;
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
await runAppleScript(script);
|
|
29
|
+
return { success: true, message: `Bildirim gonderildi: ${title}` };
|
|
30
|
+
} catch (e) {
|
|
31
|
+
return { success: false, error: e.message };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
name: "mac_notify",
|
|
37
|
+
description: "macOS Notification Center'da bildirim goster.",
|
|
38
|
+
inputSchema: {
|
|
39
|
+
type: "object",
|
|
40
|
+
properties: {
|
|
41
|
+
title: { type: "string", description: "Bildirim basligi" },
|
|
42
|
+
message: { type: "string", description: "Bildirim mesaji" },
|
|
43
|
+
subtitle: { type: "string", description: "Alt baslik (opsiyonel)" },
|
|
44
|
+
},
|
|
45
|
+
required: ["title", "message"],
|
|
46
|
+
},
|
|
47
|
+
async execute(params) {
|
|
48
|
+
return await macNotify(params);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory_search - Kalici hafiza arama (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* Hermes memory tool'una benzer ama search odakli.
|
|
5
|
+
* Kullanicinin gecmis konusmalarindan fact ve bilgi arar.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const path = require("path");
|
|
10
|
+
const os = require("os");
|
|
11
|
+
|
|
12
|
+
const MEMORY_DIR = path.join(os.homedir(), ".natureco", "memory");
|
|
13
|
+
const SESSION_DIR = path.join(os.homedir(), ".natureco", "sessions");
|
|
14
|
+
|
|
15
|
+
function listFiles(dir) {
|
|
16
|
+
try {
|
|
17
|
+
if (!fs.existsSync(dir)) return [];
|
|
18
|
+
return fs.readdirSync(dir).filter(f => f.endsWith(".json"));
|
|
19
|
+
} catch { return []; }
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function searchInObject(obj, query, path = "") {
|
|
23
|
+
const results = [];
|
|
24
|
+
if (!obj || typeof obj !== "object") return results;
|
|
25
|
+
|
|
26
|
+
if (typeof obj === "string" && obj.toLowerCase().includes(query)) {
|
|
27
|
+
return [{ path, content: obj.slice(0, 200) }];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
31
|
+
const newPath = path ? path + "." + key : key;
|
|
32
|
+
if (typeof val === "string" && val.toLowerCase().includes(query)) {
|
|
33
|
+
results.push({ path: newPath, content: val.slice(0, 200) });
|
|
34
|
+
} else if (Array.isArray(val)) {
|
|
35
|
+
val.forEach((item, i) => {
|
|
36
|
+
if (typeof item === "string" && item.toLowerCase().includes(query)) {
|
|
37
|
+
results.push({ path: newPath + "[" + i + "]", content: item.slice(0, 200) });
|
|
38
|
+
} else if (typeof item === "object") {
|
|
39
|
+
results.push(...searchInObject(item, query, newPath + "[" + i + "]"));
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else if (typeof val === "object" && val !== null) {
|
|
43
|
+
results.push(...searchInObject(val, query, newPath));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return results;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function searchMemory({ query, scope = "all", username = null, maxResults = 20 }) {
|
|
50
|
+
if (!query) return { success: false, error: "query gerekli" };
|
|
51
|
+
|
|
52
|
+
const q = query.toLowerCase();
|
|
53
|
+
const results = [];
|
|
54
|
+
const sources = [];
|
|
55
|
+
|
|
56
|
+
// Memory dosyalarini tara
|
|
57
|
+
if (scope === "all" || scope === "memory") {
|
|
58
|
+
const memoryFile = path.join(MEMORY_DIR, (username || "default") + ".json");
|
|
59
|
+
if (fs.existsSync(memoryFile)) {
|
|
60
|
+
try {
|
|
61
|
+
const mem = JSON.parse(fs.readFileSync(memoryFile, "utf8"));
|
|
62
|
+
const matches = searchInObject(mem, q, "memory");
|
|
63
|
+
matches.forEach(m => {
|
|
64
|
+
results.push({ source: "memory", ...m });
|
|
65
|
+
sources.push("memory");
|
|
66
|
+
});
|
|
67
|
+
} catch {}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Session dosyalarini tara
|
|
72
|
+
if (scope === "all" || scope === "sessions") {
|
|
73
|
+
const files = listFiles(SESSION_DIR).slice(0, 10); // Son 10 session
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
try {
|
|
76
|
+
const sess = JSON.parse(fs.readFileSync(path.join(SESSION_DIR, file), "utf8"));
|
|
77
|
+
const matches = searchInObject(sess, q, "session");
|
|
78
|
+
matches.slice(0, 3).forEach(m => {
|
|
79
|
+
results.push({ source: "session:" + file.slice(0, 12), ...m });
|
|
80
|
+
sources.push("session");
|
|
81
|
+
});
|
|
82
|
+
if (results.length >= maxResults) break;
|
|
83
|
+
} catch {}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
success: true,
|
|
89
|
+
query,
|
|
90
|
+
found: results.length,
|
|
91
|
+
results: results.slice(0, maxResults),
|
|
92
|
+
sources: [...new Set(sources)],
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = {
|
|
97
|
+
name: "memory_search",
|
|
98
|
+
description: "Kalici hafizada ve session gecmisinde arama yap. Kullici hakkinda ogrendiklerini bul.",
|
|
99
|
+
inputSchema: {
|
|
100
|
+
type: "object",
|
|
101
|
+
properties: {
|
|
102
|
+
query: { type: "string", description: "Aranacak metin" },
|
|
103
|
+
scope: { type: "string", description: "all/memory/sessions (default: all)", enum: ["all", "memory", "sessions"] },
|
|
104
|
+
username: { type: "string", description: "Kullanici adi (memory dosyasi icin)" },
|
|
105
|
+
maxResults: { type: "number", description: "Max sonuc (default 20)" },
|
|
106
|
+
},
|
|
107
|
+
required: ["query"],
|
|
108
|
+
},
|
|
109
|
+
async execute(params) {
|
|
110
|
+
return await searchMemory(params);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notebook_edit - Jupyter notebook duzenleme (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* Hermes notebook_edit'ine benzer. .ipynb dosyalarini oku, duzenle, yaz.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const path = require("path");
|
|
9
|
+
|
|
10
|
+
async function notebookEdit({ filePath, cellIndex, operation = "read", newSource = null, newType = null }) {
|
|
11
|
+
if (!filePath) return { success: false, error: "filePath gerekli" };
|
|
12
|
+
|
|
13
|
+
const resolved = path.resolve(filePath);
|
|
14
|
+
if (!fs.existsSync(resolved)) return { success: false, error: `Dosya bulunamadi: ${resolved}` };
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
const content = JSON.parse(fs.readFileSync(resolved, "utf8"));
|
|
18
|
+
|
|
19
|
+
if (operation === "read") {
|
|
20
|
+
if (cellIndex === undefined) {
|
|
21
|
+
// Tum notebook'u ozetle
|
|
22
|
+
const summary = content.cells?.map((c, i) => ({
|
|
23
|
+
index: i,
|
|
24
|
+
type: c.cell_type,
|
|
25
|
+
source: Array.isArray(c.source) ? c.source.join("") : c.source,
|
|
26
|
+
outputs: c.outputs?.length || 0,
|
|
27
|
+
})) || [];
|
|
28
|
+
return { success: true, file: resolved, cells: content.cells?.length || 0, summary };
|
|
29
|
+
}
|
|
30
|
+
const cell = content.cells?.[cellIndex];
|
|
31
|
+
if (!cell) return { success: false, error: `Hucre bulunamadi: ${cellIndex}` };
|
|
32
|
+
return { success: true, cell: { index: cellIndex, type: cell.cell_type, source: cell.source } };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (operation === "update") {
|
|
36
|
+
if (cellIndex === undefined) return { success: false, error: "cellIndex gerekli" };
|
|
37
|
+
if (newSource === undefined) return { success: false, error: "newSource gerekli" };
|
|
38
|
+
if (!content.cells?.[cellIndex]) return { success: false, error: `Hucre bulunamadi: ${cellIndex}` };
|
|
39
|
+
|
|
40
|
+
content.cells[cellIndex].source = Array.isArray(newSource) ? newSource : [newSource];
|
|
41
|
+
if (newType) content.cells[cellIndex].cell_type = newType;
|
|
42
|
+
|
|
43
|
+
fs.writeFileSync(resolved, JSON.stringify(content, null, 1), "utf8");
|
|
44
|
+
return { success: true, message: `Hucre ${cellIndex} guncellendi` };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (operation === "add") {
|
|
48
|
+
if (!newSource) return { success: false, error: "newSource gerekli" };
|
|
49
|
+
const cellType = newType || "code";
|
|
50
|
+
const newCell = {
|
|
51
|
+
cell_type: cellType,
|
|
52
|
+
source: Array.isArray(newSource) ? newSource : [newSource],
|
|
53
|
+
metadata: {},
|
|
54
|
+
};
|
|
55
|
+
if (cellType === "code") newCell.outputs = [], newCell.execution_count = null;
|
|
56
|
+
content.cells = content.cells || [];
|
|
57
|
+
content.cells.push(newCell);
|
|
58
|
+
fs.writeFileSync(resolved, JSON.stringify(content, null, 1), "utf8");
|
|
59
|
+
return { success: true, message: `Yeni hucre eklendi (index ${content.cells.length - 1})` };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (operation === "delete") {
|
|
63
|
+
if (cellIndex === undefined) return { success: false, error: "cellIndex gerekli" };
|
|
64
|
+
if (!content.cells?.[cellIndex]) return { success: false, error: `Hucre bulunamadi` };
|
|
65
|
+
content.cells.splice(cellIndex, 1);
|
|
66
|
+
fs.writeFileSync(resolved, JSON.stringify(content, null, 1), "utf8");
|
|
67
|
+
return { success: true, message: `Hucre ${cellIndex} silindi` };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { success: false, error: `Bilinmeyen operation: ${operation}` };
|
|
71
|
+
} catch (e) {
|
|
72
|
+
return { success: false, error: e.message };
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = {
|
|
77
|
+
name: "notebook_edit",
|
|
78
|
+
description: "Jupyter notebook (.ipynb) hucrelerini oku, guncelle, ekle, sil. operation: read/update/add/delete.",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
filePath: { type: "string", description: ".ipynb dosya yolu" },
|
|
83
|
+
cellIndex: { type: 'integer', description: "Hucre indeksi (0-based)" },
|
|
84
|
+
operation: { type: 'string', description: "read/update/add/delete (default: read)", enum: ["read", "update", "add", "delete"] },
|
|
85
|
+
newSource: { type: 'string', description: "Yeni hucre kaynagi (update/add icin)" },
|
|
86
|
+
newType: { type: 'string', description: "Hucre tipi: code/markdown (update/add icin)", enum: ["code", "markdown"] },
|
|
87
|
+
},
|
|
88
|
+
required: ["filePath", "operation"],
|
|
89
|
+
},
|
|
90
|
+
async execute(params) {
|
|
91
|
+
return await notebookEdit(params);
|
|
92
|
+
},
|
|
93
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* notes_add - Apple Notes'a not ekle (v4.9.1)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const IS_MAC = os.platform() === "darwin";
|
|
9
|
+
|
|
10
|
+
function runAppleScript(script) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const proc = spawn("osascript", ["-e", script]);
|
|
13
|
+
let out = ""; let err = "";
|
|
14
|
+
proc.stdout.on("data", d => out += d);
|
|
15
|
+
proc.stderr.on("data", d => err += d);
|
|
16
|
+
proc.on("close", code => code === 0 ? resolve(out.trim()) : reject(new Error(err.trim())));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function notesAdd(params) {
|
|
21
|
+
if (!IS_MAC) return { success: false, error: "Notes sadece macOS'ta" };
|
|
22
|
+
const { title, content, folder = null } = params;
|
|
23
|
+
if (!title || !content) return { success: false, error: "title ve content gerekli" };
|
|
24
|
+
|
|
25
|
+
const folderScript = folder ? `folder "${folder}"` : "default folder";
|
|
26
|
+
|
|
27
|
+
const script = `
|
|
28
|
+
tell application "Notes"
|
|
29
|
+
set targetFolder to ${folderScript}
|
|
30
|
+
set newNote to make new note at targetFolder with properties {name:"${title.replace(/"/g, "'")}", body:"${content.replace(/"/g, "'").replace(/\n/g, "\\n")}"}
|
|
31
|
+
save
|
|
32
|
+
return name of newNote
|
|
33
|
+
end tell
|
|
34
|
+
`;
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const name = await runAppleScript(script);
|
|
38
|
+
return { success: true, noteName: name, title, message: `Not eklendi: "${title}"` };
|
|
39
|
+
} catch (e) {
|
|
40
|
+
if (e.message.includes("-1743") || e.message.includes("not authorized")) {
|
|
41
|
+
return { success: false, error: "Notes erisim izni yok. System Preferences -> Security -> Automation -> Notes -> ON" };
|
|
42
|
+
}
|
|
43
|
+
return { success: false, error: e.message };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
name: "notes_add",
|
|
49
|
+
description: "Apple Notes'a yeni not ekle.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
title: { type: "string", description: "Not basligi" },
|
|
54
|
+
content: { type: "string", description: "Not icerigi" },
|
|
55
|
+
folder: { type: "string", description: "Klasor adi (default: default folder)" },
|
|
56
|
+
},
|
|
57
|
+
required: ["title", "content"],
|
|
58
|
+
},
|
|
59
|
+
async execute(params) {
|
|
60
|
+
return await notesAdd(params);
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* reminder_add - macOS Reminders'a hatirlatici ekle (v4.9.1)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { spawn } = require("child_process");
|
|
6
|
+
const os = require("os");
|
|
7
|
+
|
|
8
|
+
const IS_MAC = os.platform() === "darwin";
|
|
9
|
+
|
|
10
|
+
function runAppleScript(script) {
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const proc = spawn("osascript", ["-e", script]);
|
|
13
|
+
let out = ""; let err = "";
|
|
14
|
+
proc.stdout.on("data", d => out += d);
|
|
15
|
+
proc.stderr.on("data", d => err += d);
|
|
16
|
+
proc.on("close", code => code === 0 ? resolve(out.trim()) : reject(new Error(err.trim())));
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function reminderAdd(params) {
|
|
21
|
+
if (!IS_MAC) return { success: false, error: "Reminders sadece macOS'ta" };
|
|
22
|
+
const { title, dueDate = null, list = null, notes = "" } = params;
|
|
23
|
+
if (!title) return { success: false, error: "title gerekli" };
|
|
24
|
+
|
|
25
|
+
const listScript = list ? `list "${list}"` : `default list`;
|
|
26
|
+
const dueScript = dueDate === "today" ? "current date" : (dueDate ? `date "${dueDate}"` : "missing value");
|
|
27
|
+
|
|
28
|
+
const script = `
|
|
29
|
+
tell application "Reminders"
|
|
30
|
+
set targetList to ${listScript}
|
|
31
|
+
set newReminder to make new reminder at end of targetList with properties {name:"${title.replace(/"/g, "'")}"${notes ? `, body:"${notes.replace(/"/g, "'")}"` : ""}}
|
|
32
|
+
${dueDate ? `set due date of newReminder to ${dueScript}` : ""}
|
|
33
|
+
save
|
|
34
|
+
return id of newReminder
|
|
35
|
+
end tell
|
|
36
|
+
`;
|
|
37
|
+
|
|
38
|
+
try {
|
|
39
|
+
const id = await runAppleScript(script);
|
|
40
|
+
return { success: true, reminderId: id, title, dueDate, message: `Hatirlatici eklendi: "${title}"` };
|
|
41
|
+
} catch (e) {
|
|
42
|
+
if (e.message.includes("-1743") || e.message.includes("not authorized")) {
|
|
43
|
+
return { success: false, error: "Reminders erisim izni yok. System Preferences -> Security -> Automation -> Reminders -> ON" };
|
|
44
|
+
}
|
|
45
|
+
return { success: false, error: e.message };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
name: "reminder_add",
|
|
51
|
+
description: "macOS Reminders'a hatirlatici ekle.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
title: { type: "string", description: "Hatirlatici basligi" },
|
|
56
|
+
dueDate: { type: "string", description: 'Son tarih: "today", "+1 day", ISO "2026-06-23 14:00"' },
|
|
57
|
+
list: { type: "string", description: "Liste adi (default: default list)" },
|
|
58
|
+
notes: { type: "string", description: "Not" },
|
|
59
|
+
},
|
|
60
|
+
required: ["title"],
|
|
61
|
+
},
|
|
62
|
+
async execute(params) {
|
|
63
|
+
return await reminderAdd(params);
|
|
64
|
+
},
|
|
65
|
+
};
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* shell_command — Tek shell komutu çalıştır (v4.9.0)
|
|
3
|
+
*
|
|
4
|
+
* bash.js'den farkı: tek satır, hızlı, etkileşimsiz komutlar için.
|
|
5
|
+
* "find / -name *.log", "ls -la", "df -h" gibi.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { spawn } = require('child_process');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
|
|
11
|
+
async function runShell({ command, cwd = null, timeoutMs = 10000 }) {
|
|
12
|
+
if (!command) return { success: false, error: 'command gerekli' };
|
|
13
|
+
|
|
14
|
+
return new Promise((resolve) => {
|
|
15
|
+
const proc = spawn('bash', ['-c', command], {
|
|
16
|
+
cwd: cwd || os.homedir(),
|
|
17
|
+
timeout: timeoutMs,
|
|
18
|
+
env: { ...process.env, FORCE_COLOR: '0' },
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
let stdout = '';
|
|
22
|
+
let stderr = '';
|
|
23
|
+
proc.stdout.on('data', d => stdout += d.toString());
|
|
24
|
+
proc.stderr.on('data', d => stderr += d.toString());
|
|
25
|
+
|
|
26
|
+
proc.on('close', (code) => {
|
|
27
|
+
const truncated = (s) => s.length > 8000 ? s.slice(0, 8000) + '\n... (kesildi)' : s;
|
|
28
|
+
resolve({
|
|
29
|
+
success: code === 0,
|
|
30
|
+
command,
|
|
31
|
+
exitCode: code,
|
|
32
|
+
stdout: truncated(stdout).trim(),
|
|
33
|
+
stderr: truncated(stderr).trim(),
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
proc.on('error', (e) => resolve({ success: false, error: e.message, command }));
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module.exports = {
|
|
41
|
+
name: 'shell_command',
|
|
42
|
+
description: 'Tek shell komutu çalıştır (find, ls, grep, cat, df, ps, vb.). Etkileşimsiz komutlar için. 10s timeout.',
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
command: { type: 'string', description: 'Çalıştırılacak shell komutu (örn: "ls -la ~/Documents")' },
|
|
47
|
+
cwd: { type: 'string', description: 'Çalışma dizini' },
|
|
48
|
+
timeoutMs: { type: 'number', description: 'Timeout ms (default 10000)' },
|
|
49
|
+
},
|
|
50
|
+
required: ['command'],
|
|
51
|
+
},
|
|
52
|
+
async execute(params) {
|
|
53
|
+
return await runShell(params);
|
|
54
|
+
},
|
|
55
|
+
};
|