Project Files
deepeditor-tools / src / toolsProvider.ts
// src/toolsProvider.ts
import { text, tool, type Tool, type ToolsProviderController } from "@lmstudio/sdk";
import { spawn } from "child_process";
import {
rm, writeFile, readFile, mkdir, cp, rename,
readdir, stat, access
} from "fs/promises";
import { join, normalize, dirname, extname, resolve } from "path";
import { z } from "zod";
import { existsSync, readdirSync } from "fs"; // ← أضفنا readdirSync هنا
import ExcelJS from "exceljs";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1. الثوابت والإعدادات العامة
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const UNSAFE = true;
const targetBase = normalize("D:\\bido");
const MEMORY_BASE = join(targetBase, "2026", "final_memory");
const SESSIONS_DIR = join(MEMORY_BASE, "sessions");
const RAW_SESSIONS_DIR = join(MEMORY_BASE, "raw_sessions");
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. الدوال المساعدة (غير مسجلة كأدوات)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async function ensureDirectory(dirPath: string) {
if (!existsSync(dirPath)) await mkdir(dirPath, { recursive: true });
}
function resolveInsideBase(rel: string): string {
const isAbs = /^([A-Za-z]:)?[\\\/]/.test(rel);
return normalize(isAbs ? rel : join(targetBase, rel));
}
function getNextSessionNumber(): number {
if (!existsSync(SESSIONS_DIR)) return 1;
const files = readdirSync(SESSIONS_DIR);
const nums: number[] = files
.filter((f: string) => f.startsWith("session") && f.endsWith(".json"))
.map((f: string) => parseInt(f.replace("session", "").replace(".json", ""), 10))
.filter((n: number) => !isNaN(n));
return nums.length ? Math.max(...nums) + 1 : 1;
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 3. أدوات الذاكرة (save_session, get_memory, read_raw_session)
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async function saveSessionTool(params: {
title: string;
main_idea: string;
sub_ideas?: string[];
summary: string;
tags?: string[];
raw_content: string;
}) {
await ensureDirectory(SESSIONS_DIR);
await ensureDirectory(RAW_SESSIONS_DIR);
const nextNum = getNextSessionNumber();
const sessionId = `session${String(nextNum).padStart(2, "0")}`;
const jsonContent = {
session_id: sessionId,
title: params.title,
main_idea: params.main_idea,
sub_ideas: params.sub_ideas || [],
summary: params.summary,
tags: params.tags || [],
timestamp: new Date().toISOString(),
raw_file: `raw_sessions/${sessionId}.md`,
};
const jsonPath = join(SESSIONS_DIR, `${sessionId}.json`);
const rawPath = join(RAW_SESSIONS_DIR, `${sessionId}.md`);
await writeFile(jsonPath, JSON.stringify(jsonContent, null, 2), "utf-8");
await writeFile(rawPath, params.raw_content, "utf-8");
return {
success: true,
message: `✅ تم حفظ الجلسة ${sessionId}`,
session_id: sessionId,
json_path: jsonPath,
raw_path: rawPath,
};
}
async function getMemoryTool(params: {
query?: string;
tag?: string;
limit?: number;
threshold?: number;
}) {
const { query, tag, limit = 5, threshold = 0.3 } = params;
if (!existsSync(SESSIONS_DIR)) {
return { success: true, results: [], totalFound: 0, returned: 0 };
}
const files = (await readdir(SESSIONS_DIR)).filter(f => f.endsWith(".json"));
const results: any[] = [];
for (const file of files) {
const content = await readFile(join(SESSIONS_DIR, file), "utf-8");
const session = JSON.parse(content);
let relevance = 0;
const matchReasons: string[] = [];
if (query) {
const q = query.toLowerCase();
if (session.title?.toLowerCase().includes(q)) {
relevance += 0.4;
matchReasons.push("مطابقة في العنوان");
}
if (session.main_idea?.toLowerCase().includes(q)) {
relevance += 0.3;
matchReasons.push("مطابقة في الفكرة الرئيسية");
}
if (session.summary?.toLowerCase().includes(q)) {
relevance += 0.2;
matchReasons.push("مطابقة في الملخص");
}
if (session.sub_ideas?.some((s: string) => s.toLowerCase().includes(q))) {
relevance += 0.1;
matchReasons.push("مطابقة في الأفكار الفرعية");
}
if (session.tags?.some((t: string) => t.toLowerCase().includes(q))) {
relevance += 0.3;
matchReasons.push("مطابقة في التاجات");
}
}
if (tag && session.tags?.includes(tag)) {
relevance += 0.5;
matchReasons.push(`مطابقة تاج: ${tag}`);
}
relevance = Math.min(relevance, 1);
if (relevance >= threshold) {
results.push({
session_id: session.session_id,
title: session.title,
summary: session.summary,
tags: session.tags,
timestamp: session.timestamp,
relevance,
matchReasons: matchReasons.length ? matchReasons : ["مطابقة عامة"],
raw_file: session.raw_file,
});
}
}
results.sort((a, b) => b.relevance - a.relevance);
const returned = results.slice(0, limit);
return {
success: true,
query: query || null,
filters: { tag: tag || null, limit, threshold },
results: returned,
totalFound: results.length,
returned: returned.length,
};
}
async function readRawSessionTool(params: { raw_file: string }) {
const rawPath = resolveInsideBase(params.raw_file);
if (!existsSync(rawPath)) {
return { success: false, error: `الملف الخام غير موجود: ${params.raw_file}` };
}
const content = await readFile(rawPath, "utf-8");
return {
success: true,
path: rawPath,
content,
message: "✅ تمت قراءة الملف الخام بنجاح",
};
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 4. الأدوات الذكية الجديدة
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async function eagleEye(filePath: string) {
try {
const fullPath = resolveInsideBase(filePath);
const fileStat = await stat(fullPath);
const content = await readFile(fullPath, "utf-8");
const lines = content.split("\n");
const words = content.split(/\s+/);
const chars = content.length;
const suspicious = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
const hasSuspicious = suspicious.test(content);
let structure: any = {};
const ext = extname(filePath).toLowerCase();
if (ext === ".html" || ext === ".htm") {
structure = {
type: "HTML",
divs: (content.match(/<div/g) || []).length,
classes: (content.match(/class=["']([^"']*)["']/g) || []).length,
ids: (content.match(/id=["']([^"']*)["']/g) || []).length,
scripts: (content.match(/<script/g) || []).length,
links: (content.match(/<a\s+href=/g) || []).length,
};
} else if (ext === ".js" || ext === ".ts") {
structure = {
type: ext === ".js" ? "JavaScript" : "TypeScript",
functions: (content.match(/function\s+\w+\s*\(/g) || []).length,
classes: (content.match(/class\s+\w+/g) || []).length,
imports: (content.match(/import\s+.*from/g) || []).length,
exports: (content.match(/export\s+/g) || []).length,
};
} else if (ext === ".py") {
structure = {
type: "Python",
functions: (content.match(/def\s+\w+\s*\(/g) || []).length,
classes: (content.match(/class\s+\w+/g) || []).length,
imports: (content.match(/import\s+\w+/g) || []).length,
fromImports: (content.match(/from\s+\w+\s+import/g) || []).length,
};
} else if (ext === ".json") {
try {
const parsed = JSON.parse(content);
structure = {
type: "JSON",
keys: Object.keys(parsed).length,
isArray: Array.isArray(parsed),
depth: JSON.stringify(parsed).match(/[{[]/g)?.length || 0,
};
} catch {
structure = { type: "JSON (غير صالح)" };
}
} else if (ext === ".md") {
structure = {
type: "Markdown",
headings: (content.match(/^#+/gm) || []).length,
lists: (content.match(/^[\s]*[-*+]\s/gm) || []).length,
codeBlocks: (content.match(/```/g) || []).length / 2,
};
} else {
structure = { type: "text", lines: lines.length, words: words.length };
}
let preview = lines.slice(0, 30).join("\n");
if (preview.length > 2000) preview = preview.slice(0, 2000) + "\n... (مقتطع)";
return {
success: true,
file: filePath,
size: fileStat.size,
lines: lines.length,
words: words.length,
chars,
hasSuspicious,
structure,
preview,
recommendation: hasSuspicious ? "⚠️ يحتوي على رموز خبيثة محتملة" : "✅ آمن للقراءة",
};
} catch (error: any) {
return { success: false, error: error.message, file: filePath };
}
}
async function searchFilesTool(params: {
searchPath: string;
query: string;
searchType?: "name" | "content";
}) {
const { searchPath, query, searchType = "name" } = params;
const results: any[] = [];
let scanned = 0;
const maxResults = 100;
const maxDepth = 10;
const excludeDirs = [
"$RECYCLE.BIN",
"System Volume Information",
"Windows",
"Program Files",
"Program Files (x86)",
"node_modules",
".git",
"temp",
"tmp",
"cache",
"logs",
"backup",
];
const excludeExt = [".exe", ".dll", ".bin", ".iso", ".zip", ".rar", ".7z"];
async function scan(dir: string, depth: number = 0) {
if (depth > maxDepth || results.length >= maxResults) return;
try {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
if (
excludeDirs.includes(entry.name) ||
entry.name.startsWith(".") ||
entry.name.startsWith("$")
) continue;
const fullPath = join(dir, entry.name);
if (entry.isDirectory()) {
await scan(fullPath, depth + 1);
} else {
const ext = extname(entry.name).toLowerCase();
if (excludeExt.includes(ext)) continue;
scanned++;
if (searchType === "name") {
if (entry.name.toLowerCase().includes(query.toLowerCase())) {
results.push({ path: fullPath, name: entry.name, size: (await stat(fullPath)).size });
}
} else {
try {
const stats = await stat(fullPath);
if (stats.size > 5 * 1024 * 1024) continue;
const content = await readFile(fullPath, "utf-8");
if (content.toLowerCase().includes(query.toLowerCase())) {
results.push({ path: fullPath, name: entry.name, size: stats.size });
}
} catch {}
}
}
}
} catch {}
}
try {
const fullPath = resolveInsideBase(searchPath);
await scan(fullPath);
return {
success: true,
results: results.slice(0, 50),
total: results.length,
scanned,
searchType,
maxResultsReached: results.length >= maxResults,
};
} catch (error: any) {
return { success: false, error: error.message };
}
}
async function ocrImageTool(params: { imagePath: string; language?: string }) {
const { imagePath, language = "ara+eng" } = params;
try {
const fullPath = resolveInsideBase(imagePath);
if (!existsSync(fullPath)) {
return { success: false, error: `الملف غير موجود: ${imagePath}` };
}
const tesseractPaths = [
"D:\\ocr\\Tesseract-OCR\\tesseract.exe",
"C:\\Program Files\\Tesseract-OCR\\tesseract.exe",
"C:\\Program Files (x86)\\Tesseract-OCR\\tesseract.exe",
];
let tesseractPath: string | null = null;
for (const p of tesseractPaths) {
if (existsSync(p)) {
tesseractPath = p;
break;
}
}
if (!tesseractPath) {
const { stdout } = await execAsync(`where tesseract 2>nul`).catch(() => ({ stdout: "" }));
if (stdout.trim()) tesseractPath = stdout.trim().split("\n")[0];
}
if (!tesseractPath) {
return {
success: false,
error: "Tesseract غير مثبت",
hint: "قم بتثبيت Tesseract OCR من: https://github.com/UB-Mannheim/tesseract/wiki",
paths: tesseractPaths,
};
}
const { stdout, stderr } = await execAsync(
`"${tesseractPath}" "${fullPath}" stdout -l ${language} 2>nul`
);
if (stderr && !stderr.includes("Tesseract Open Source")) {
return { success: false, error: stderr };
}
const text = stdout.trim();
if (!text) {
return {
success: false,
error: "لم يتم استخراج أي نص من الصورة",
hint: "تأكد من أن الصورة تحتوي على نص واضح",
};
}
return {
success: true,
text,
language,
words: text.split(/\s+/).length,
chars: text.length,
lines: text.split("\n").length,
};
} catch (error: any) {
return { success: false, error: error.message };
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 5. التسجيل النهائي للأدوات في LM Studio
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
export async function toolsProvider(ctl: ToolsProviderController): Promise<Tool[]> {
const tools: Tool[] = [];
// ── أدوات الملفات والمجلدات ──
tools.push(tool({
name: "writeFile",
description: text`اكتب/أنشئ الملف في المسار المحدد (UTF-8)`,
parameters: { file: z.string().min(1), content: z.string() },
implementation: async ({ file, content }) => {
const path = resolveInsideBase(file);
await ensureDirectory(dirname(path));
await writeFile(path, content, "utf-8");
return { success: true, message: `تم كتابة الملف ${file}` };
},
}));
tools.push(tool({
name: "readFile",
description: text`اقرأ الملف وأرجع المحتوى كاملاً (UTF-8)`,
parameters: { file: z.string().min(1) },
implementation: async ({ file }) => {
const path = resolveInsideBase(file);
if (!existsSync(path)) return { success: false, error: `الملف ${file} غير موجود` };
const content = await readFile(path, "utf-8");
return { success: true, content };
},
}));
tools.push(tool({
name: "renameFile",
description: text`أعد تسمية/انقل الملف`,
parameters: { oldName: z.string().min(1), newName: z.string().min(1) },
implementation: async ({ oldName, newName }) => {
const oldPath = resolveInsideBase(oldName);
const newPath = resolveInsideBase(newName);
if (!existsSync(oldPath)) return { success: false, error: `الملف ${oldName} غير موجود` };
await ensureDirectory(dirname(newPath));
await rename(oldPath, newPath);
return { success: true, message: `تمت إعادة التسمية إلى ${newName}` };
},
}));
tools.push(tool({
name: "deleteFile",
description: text`احذف ملفًا`,
parameters: { file: z.string().min(1) },
implementation: async ({ file }) => {
const path = resolveInsideBase(file);
if (!existsSync(path)) return { success: false, error: `الملف ${file} غير موجود` };
await rm(path, { force: true });
return { success: true, message: `تم حذف الملف ${file}` };
},
}));
tools.push(tool({
name: "copyFile",
description: text`انسخ الملف`,
parameters: { from: z.string().min(1), to: z.string().min(1), overwrite: z.boolean().optional() },
implementation: async ({ from, to, overwrite }) => {
const fromPath = resolveInsideBase(from);
const toPath = resolveInsideBase(to);
if (!existsSync(fromPath)) return { success: false, error: `الملف ${from} غير موجود` };
await ensureDirectory(dirname(toPath));
await cp(fromPath, toPath, { force: !!overwrite, errorOnExist: !overwrite });
return { success: true, message: `تم نسخ ${from} إلى ${to}` };
},
}));
tools.push(tool({
name: "listDirectoryStructure",
description: text`اعرض محتويات المجلد`,
parameters: { folder: z.string().default("") },
implementation: async ({ folder }) => {
const dir = resolveInsideBase(folder || "");
if (!existsSync(dir)) return { success: false, error: `المجلد غير موجود` };
const entries = await readdir(dir, { withFileTypes: true });
const items = await Promise.all(entries.map(async (e) => {
const p = join(dir, e.name);
const s = await stat(p);
return { name: e.name, type: e.isDirectory() ? "مجلد" : "ملف", size: e.isDirectory() ? "-" : `${(s.size/1024).toFixed(2)} KB`, modified: s.mtime.toISOString() };
}));
return { success: true, folder: folder || "[الجذر]", items };
},
}));
tools.push(tool({
name: "createFolder",
description: text`أنشئ مجلدًا`,
parameters: { folder: z.string().min(1) },
implementation: async ({ folder }) => {
await mkdir(resolveInsideBase(folder), { recursive: true });
return { success: true, message: `تم إنشاء المجلد ${folder}` };
},
}));
tools.push(tool({
name: "deleteFolder",
description: text`احذف مجلدًا (قوة)`,
parameters: { folder: z.string().min(1) },
implementation: async ({ folder }) => {
const path = resolveInsideBase(folder);
if (!existsSync(path)) return { success: false, error: `المجلد ${folder} غير موجود` };
await rm(path, { recursive: true, force: true });
return { success: true, message: `تم حذف المجلد ${folder}` };
},
}));
tools.push(tool({
name: "renameFolder",
description: text`أعد تسمية مجلد`,
parameters: { oldPath: z.string().min(1), newPath: z.string().min(1) },
implementation: async ({ oldPath, newPath }) => {
await rename(resolveInsideBase(oldPath), resolveInsideBase(newPath));
return { success: true, message: `تمت إعادة تسمية المجلد` };
},
}));
tools.push(tool({
name: "moveFolder",
description: text`انقل مجلد`,
parameters: { source: z.string().min(1), dest: z.string().min(1) },
implementation: async ({ source, dest }) => {
await rename(resolveInsideBase(source), resolveInsideBase(dest));
return { success: true, message: `تم نقل المجلد` };
},
}));
// ── الوقت والتاريخ ──
tools.push(tool({
name: "getCurrentTime",
description: text`أرجع الوقت الحالي`,
parameters: {},
implementation: async () => {
const now = new Date();
return { success: true, time: now.toLocaleTimeString("ar"), iso: now.toISOString(), timezone: Intl.DateTimeFormat().resolvedOptions().timeZone };
},
}));
tools.push(tool({
name: "getCurrentDate",
description: text`أرجع التاريخ الحالي`,
parameters: {},
implementation: async () => {
const today = new Date();
return { success: true, date: today.toLocaleDateString("ar"), isoDate: today.toISOString().slice(0, 10) };
},
}));
// ── أدوات الذاكرة الجديدة ──
tools.push(tool({
name: "save_session",
description: text`احفظ الجلسة الحالية كملف JSON و Markdown`,
parameters: {
title: z.string().max(100),
main_idea: z.string().max(300),
sub_ideas: z.array(z.string()).default([]),
summary: z.string().max(500),
tags: z.array(z.string()).default([]),
raw_content: z.string(),
},
implementation: saveSessionTool,
}));
tools.push(tool({
name: "get_memory",
description: text`ابحث في جلسات الذاكرة المخزنة`,
parameters: {
query: z.string().optional(),
tag: z.string().optional(),
limit: z.number().int().min(1).max(20).default(5),
threshold: z.number().min(0).max(1).default(0.3),
},
implementation: getMemoryTool,
}));
tools.push(tool({
name: "read_raw_session",
description: text`اقرأ الملف الخام (Markdown) لجلسة سابقة`,
parameters: { raw_file: z.string().min(1) },
implementation: readRawSessionTool,
}));
// ── أدوات Excel ──
tools.push(tool({
name: "readExcelSheet",
description: text`اقرأ ورقة من ملف Excel`,
parameters: { file: z.string().min(1), sheet: z.string().optional() },
implementation: async ({ file, sheet }) => {
const path = resolveInsideBase(file.endsWith(".xlsx") ? file : `${file}.xlsx`);
if (!existsSync(path)) return { success: false, error: `الملف غير موجود` };
const wb = new ExcelJS.Workbook();
await wb.xlsx.readFile(path);
const ws = sheet ? wb.getWorksheet(sheet) : wb.worksheets[0];
if (!ws) return { success: false, error: `لا توجد ورقة مطابقة` };
const rows: any[] = [];
ws.eachRow((row) => {
const vals: any[] = [];
row.eachCell({ includeEmpty: true }, (cell) => vals.push(cell.value));
rows.push(vals);
});
return { success: true, rows, sheet: ws.name };
},
}));
tools.push(tool({
name: "appendExcelRow",
description: text`أضف صفًا إلى ورقة Excel`,
parameters: { file: z.string().min(1), sheet: z.string().optional(), row: z.array(z.union([z.string(), z.number(), z.boolean()])).min(1) },
implementation: async ({ file, sheet, row }) => {
const path = resolveInsideBase(file.endsWith(".xlsx") ? file : `${file}.xlsx`);
const wb = new ExcelJS.Workbook();
if (existsSync(path)) await wb.xlsx.readFile(path);
let ws = sheet ? wb.getWorksheet(sheet) : wb.worksheets[0];
if (!ws) ws = wb.addWorksheet(sheet || "Sheet1");
ws.addRow(row);
await ensureDirectory(dirname(path));
await wb.xlsx.writeFile(path);
return { success: true, message: `تمت إضافة صف إلى ${ws.name}` };
},
}));
// ── أدوات تنفيذ الكود ──
tools.push(tool({
name: "runCode",
description: text`نفّذ JavaScript أو Python`,
parameters: {
language: z.enum(["javascript", "python"]).default("javascript"),
code: z.string().optional(),
file: z.string().optional(),
args: z.array(z.string()).optional(),
timeoutMs: z.number().int().min(0).max(3600000).optional(),
},
implementation: async ({ language, code, file, args, timeoutMs }) => {
const scriptPath = file ? resolveInsideBase(file) : join(targetBase, "scripts", `tmp_${Date.now()}.${language === "python" ? "py" : "js"}`);
if (code) await writeFile(scriptPath, code, "utf-8");
const cmd = language === "python" ? "python" : "node";
const result = await new Promise<any>((resolve) => {
const child = spawn(cmd, [scriptPath, ...(args || [])], { cwd: dirname(scriptPath) });
let stdout = "", stderr = "";
child.stdout?.on("data", (d) => stdout += d);
child.stderr?.on("data", (d) => stderr += d);
child.on("close", (code) => resolve({ success: code === 0, stdout, stderr, code }));
child.on("error", (err) => resolve({ success: false, stdout, stderr, error: err.message }));
});
return { ...result, script: scriptPath, language };
},
}));
// ── الأوامر الطبيعية ──
tools.push(tool({
name: "arabicorenglishCommand",
description: text`نفّذ أوامر عربية أو إنجليزية طبيعية`,
parameters: { instruction: z.string().min(1), content: z.string().optional() },
implementation: async ({ instruction, content }) => {
const s = instruction.trim();
const saveRe = /(احفظ|اكتب|انشئ|create |save |new)\s+(?:ملف\s+)?(?:"([^"]+)"|'([^']+)'|(\S+))(?:\s+(?:بمحتوى|بمحتوى:|بمحتوى\\:)\s+(?:"([\s\S]+)"|'([\s\S]+)'|([\s\S]+)))?$/i;
const readRe = /(اقرأ|افتح| read| open)\s+(?:"([^"]+)"|'([^']+)'|(\S+))/i;
const delRe = /(احذف|امسح| delete)\s+(?:"([^"]+)"|'([^']+)'|(\S+))/i;
const listRe = /(اعرض|استعرض|قائمة|الملفات|list |show| view)(?:\s+(?:في|داخل)\s+(?:"([^"]+)"|'([^']+)'|(\S+)))?/i;
const mSave = s.match(saveRe);
if (mSave) {
const file = mSave[2] || mSave[3] || mSave[4];
const body = mSave[5] || mSave[6] || mSave[7] || content || "";
const path = resolveInsideBase(file);
await ensureDirectory(dirname(path));
await writeFile(path, body, "utf-8");
return { success: true, message: `تم حفظ الملف ${file}` };
}
const mRead = s.match(readRe);
if (mRead) {
const file = mRead[2] || mRead[3] || mRead[4];
const path = resolveInsideBase(file);
if (!existsSync(path)) return { success: false, error: `الملف ${file} غير موجود` };
const data = await readFile(path, "utf-8");
return { success: true, content: data };
}
const mDel = s.match(delRe);
if (mDel) {
const file = mDel[2] || mDel[3] || mDel[4];
const path = resolveInsideBase(file);
if (!existsSync(path)) return { success: false, error: `الملف ${file} غير موجود` };
await rm(path, { force: true });
return { success: true, message: `تم حذف ${file}` };
}
const mList = s.match(listRe);
if (mList) {
const folder = mList[2] || mList[3] || mList[4] || ".";
const dir = resolveInsideBase(folder);
if (!existsSync(dir)) return { success: false, error: `المجلد غير موجود` };
const entries = await readdir(dir, { withFileTypes: true });
const items = await Promise.all(entries.map(async (e) => {
const p = join(dir, e.name);
const st = await stat(p);
return { name: e.name, type: e.isDirectory() ? "مجلد" : "ملف", size: e.isDirectory() ? "-" : `${(st.size/1024).toFixed(2)} KB`, modified: st.mtime.toISOString() };
}));
return { success: true, folder, items };
}
return { success: true, message: "تم تمرير النص للتحليل الإدراكي.", raw: instruction };
},
}));
// ── أدوات الديناميك ──
tools.push(tool({
name: "dynamicTool",
description: text`أنشئ أداة ديناميكية`,
parameters: {
tool_name: z.string().min(1),
language: z.enum(["python", "javascript"]).default("javascript"),
code: z.string().min(1),
purpose: z.string().optional(),
functions: z.array(z.string()).optional(),
args: z.array(z.string()).optional(),
run: z.boolean().default(true),
},
implementation: async ({ tool_name, language, code, purpose, functions, args, run }) => {
const dynDir = join(targetBase, "dynamic_tools");
await ensureDirectory(dynDir);
const ext = language === "python" ? ".py" : ".js";
const codePath = join(dynDir, `${tool_name}${ext}`);
await writeFile(codePath, code, "utf-8");
let result: any = { success: true, message: "تم إنشاء الأداة", path: codePath };
if (run) {
const cmd = language === "python" ? "python" : "node";
const res = await new Promise<any>((resolve) => {
const child = spawn(cmd, [codePath, ...(args || [])], { cwd: dynDir });
let stdout = "", stderr = "";
child.stdout?.on("data", (d) => stdout += d);
child.stderr?.on("data", (d) => stderr += d);
child.on("close", (code) => resolve({ success: code === 0, stdout, stderr, code }));
});
result = { ...result, ...res };
}
return result;
},
}));
tools.push(tool({
name: "runDynamicTool",
description: text`شغّل أداة ديناميكية`,
parameters: {
tool_name: z.string().min(1),
language: z.enum(["python", "javascript"]).default("javascript"),
args: z.array(z.string()).optional(),
timeoutMs: z.number().int().min(0).max(3600000).optional(),
},
implementation: async ({ tool_name, language, args }) => {
const ext = language === "python" ? ".py" : ".js";
const codePath = join(targetBase, "dynamic_tools", `${tool_name}${ext}`);
if (!existsSync(codePath)) return { success: false, error: `الأداة غير موجودة` };
const cmd = language === "python" ? "python" : "node";
return await new Promise<any>((resolve) => {
const child = spawn(cmd, [codePath, ...(args || [])], { cwd: dirname(codePath) });
let stdout = "", stderr = "";
child.stdout?.on("data", (d) => stdout += d);
child.stderr?.on("data", (d) => stderr += d);
child.on("close", (code) => resolve({ success: code === 0, stdout, stderr, code }));
child.on("error", (err) => resolve({ success: false, error: err.message }));
});
},
}));
// ── الأدوات الذكية الجديدة ──
tools.push(tool({
name: "eagleEye",
description: text`🦅 تحليل عميق للملفات (حجم، بنية، اكتشاف رموز خبيثة)`,
parameters: { filePath: z.string().describe("مسار الملف للتحليل") },
implementation: async (args: { filePath: string }) => eagleEye(args.filePath),
}));
tools.push(tool({
name: "searchFiles",
description: text`🔍 بحث سريع في الملفات (بالاسم أو المحتوى)`,
parameters: {
searchPath: z.string().describe("مسار البحث"),
query: z.string().describe("النص المطلوب"),
searchType: z.enum(["name", "content"]).default("name").describe("نوع البحث"),
},
implementation: async (args: { searchPath: string; query: string; searchType?: "name" | "content" }) =>
searchFilesTool(args),
}));
tools.push(tool({
name: "ocrImage",
description: text`📷 استخراج النص من الصور باستخدام Tesseract`,
parameters: {
imagePath: z.string().describe("مسار الصورة"),
language: z.string().default("ara+eng").describe("لغة OCR"),
},
implementation: async (args: { imagePath: string; language?: string }) =>
ocrImageTool(args),
}));
return tools;
}