dist / toolsProvider.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.toolsProvider = toolsProvider;
// src/toolsProvider.ts
const sdk_1 = require("@lmstudio/sdk");
const zod_1 = require("zod");
const promises_1 = require("fs/promises");
const path_1 = require("path");
const fs_1 = require("fs");
const findLMStudioHome_js_1 = require("./findLMStudioHome.js");
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1. الثوابت والمسارات
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const LMSTUDIO_HOME = (0, findLMStudioHome_js_1.findLMStudioHome)();
const targetBase = process.env.DEEPEDITOR_BASE || (0, path_1.normalize)("D:\\bido");
function resolveInsideBase(rel) {
const isAbs = /^([A-Za-z]:)?[\\\/]/.test(rel);
return (0, path_1.normalize)(isAbs ? rel : (0, path_1.join)(targetBase, rel));
}
async function ensureDirectory(dirPath) {
if (!(0, fs_1.existsSync)(dirPath))
await (0, promises_1.mkdir)(dirPath, { recursive: true });
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. دوال الأدوات المستقلة
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ── أداة البحث على الإنترنت (مستقلة) ──
async function searchWebTool(params) {
try {
// استيراد serpapi ديناميكياً (لتفادي مشاكل التحميل)
const { getJson } = await Promise.resolve().then(() => __importStar(require('serpapi')));
const API_KEY = 'cd86d518973b79f8e6600672666bff94c590e4b0d2f50be247a2659c03ec1b62';
console.log('🔍 جاري البحث عن: "' + params.query + '" عبر SerpAPI...');
const response = await getJson({
engine: 'google_news',
api_key: API_KEY,
q: params.query,
hl: 'ar',
gl: 'eg',
num: params.maxResults || 5
});
let results = [];
if (response.news_results && response.news_results.length > 0) {
for (let i = 0; i < response.news_results.length && i < (params.maxResults || 5); i++) {
const item = response.news_results[i];
if (!item.link || item.link === '#')
continue;
let source = 'Google News';
if (item.source) {
if (typeof item.source === 'string')
source = item.source;
else if (item.source.name)
source = item.source.name;
}
let snippet = item.snippet || item.description || item.summary || '';
if (typeof snippet !== 'string')
snippet = JSON.stringify(snippet);
if (!snippet || snippet === 'لا يوجد وصف' || snippet.trim() === '') {
snippet = item.title || 'لا يوجد وصف';
}
let published = item.date || new Date().toISOString();
if (typeof published !== 'string')
published = JSON.stringify(published);
let title = item.title || 'بدون عنوان';
title = title.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
results.push({ title, url: item.link, snippet, source, published });
}
}
// إذا لم تكن هناك نتائج عربية، جرب الإنجليزية
if (results.length === 0) {
console.log('⚠️ لا توجد نتائج عربية، جاري البحث بالإنجليزية...');
const cleanQuery = params.query.replace(/[^\w\s]/g, '').trim();
const englishResponse = await getJson({
engine: 'google_news',
api_key: API_KEY,
q: cleanQuery || 'artificial intelligence',
hl: 'en',
gl: 'us',
num: params.maxResults || 5
});
if (englishResponse.news_results) {
for (let j = 0; j < englishResponse.news_results.length && j < (params.maxResults || 5); j++) {
const item = englishResponse.news_results[j];
if (!item.link || item.link === '#')
continue;
let source = 'Google News';
if (item.source) {
if (typeof item.source === 'string')
source = item.source;
else if (item.source.name)
source = item.source.name;
}
let snippet = item.snippet || item.description || item.summary || '';
if (typeof snippet !== 'string')
snippet = JSON.stringify(snippet);
if (!snippet || snippet === 'لا يوجد وصف' || snippet.trim() === '') {
snippet = item.title || 'لا يوجد وصف';
}
let published = item.date || new Date().toISOString();
if (typeof published !== 'string')
published = JSON.stringify(published);
let title = item.title || 'بدون عنوان';
title = title.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
results.push({ title, url: item.link, snippet, source, published });
}
}
}
if (results.length === 0) {
return {
success: false,
error: 'لم يتم العثور على نتائج',
system_note: '🌐 تم البحث عن "' + params.query + '" في google'
};
}
let displayLines = ['🌐 نتائج البحث عن: ' + params.query];
for (let i = 0; i < results.length; i++) {
const r = results[i];
displayLines.push('\n' + (i + 1) + '. ' + r.title, ' 📰 ' + r.source + ' | 📅 ' + r.published, ' 📄 ' + r.snippet, ' 🔗 ' + r.url);
}
return {
success: true,
results: results,
display: displayLines.join('\n'),
total: results.length,
system_note: '🌐 تم البحث عن "' + params.query + '" في google'
};
}
catch (error) {
console.error('❌ خطأ في البحث:', error.message);
return {
success: false,
error: 'فشل البحث: ' + error.message,
system_note: '⚠️ فشل البحث: ' + error.message
};
}
}
// ── أداة تحميل المقالات (مستقلة) ──
async function fetchArticleTool(params) {
try {
// استيراد node-fetch ديناميكياً
const fetch = (await Promise.resolve().then(() => __importStar(require('node-fetch')))).default;
console.log('📥 جاري تحميل المقال من: ' + params.url);
const response = await fetch(params.url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
const html = await response.text();
// استخراج العنوان
let title = 'بدون عنوان';
const titleMatch = html.match(/<title>(.*?)<\/title>/);
if (titleMatch) {
title = titleMatch[1].replace(/<[^>]*>/g, '').trim();
}
// تنظيف النص
let textContent = html
.replace(/<script[\s\S]*?<\/script>/g, ' ')
.replace(/<style[\s\S]*?<\/style>/g, ' ')
.replace(/<[^>]*>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
// اختصار النص
const maxChars = 5000;
let content = textContent;
if (content.length > maxChars) {
content = content.substring(0, maxChars) + '\n\n... (المقال مختصر)';
}
// إنشاء اسم الملف
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
const safeTitle = title.replace(/[^a-zA-Z0-9\u0600-\u06FF]/g, '_').slice(0, 50);
const fileName = params.filename || safeTitle + '_' + timestamp;
const saveDir = (0, path_1.join)(targetBase, 'internet_search_results');
if (!(0, fs_1.existsSync)(saveDir)) {
(0, fs_1.mkdirSync)(saveDir, { recursive: true });
}
const filePath = (0, path_1.join)(saveDir, fileName + '.md');
const markdownContent = '# ' + title + '\n\n' +
'**المصدر:** ' + params.url + '\n' +
'**تاريخ التحميل:** ' + new Date().toLocaleString('ar-EG') + '\n\n' +
'---\n\n' +
content;
(0, fs_1.writeFileSync)(filePath, markdownContent, 'utf-8');
console.log('✅ تم حفظ المقال في: ' + filePath);
return {
success: true,
message: '✅ تم حفظ المقال في: ' + filePath,
file: filePath,
title: title,
wordCount: textContent.split(/\s+/).length,
charCount: textContent.length
};
}
catch (error) {
console.error('❌ خطأ في تحميل المقال:', error.message);
return {
success: false,
error: 'فشل تحميل المقال: ' + error.message
};
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 3. التسجيل النهائي في LM Studio
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async function toolsProvider(ctl) {
const tools = [];
// ── 1. كتابة ملف متقدم ──
tools.push((0, sdk_1.tool)({
name: "writeFileadvanced",
description: (0, sdk_1.text) `اكتب محتوى إلى ملف (ينشئ المجلدات تلقائياً)`,
parameters: {
file: zod_1.z.string().min(1).describe("مسار الملف"),
content: zod_1.z.string().describe("المحتوى المراد كتابته"),
},
implementation: async ({ file, content }) => {
try {
const path = resolveInsideBase(file);
await ensureDirectory((0, path_1.dirname)(path));
await (0, promises_1.writeFile)(path, content, "utf-8");
return { success: true, message: `تم كتابة الملف ${file}` };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 2. قراءة ملف متقدم ──
tools.push((0, sdk_1.tool)({
name: "readFileadvanced",
description: (0, sdk_1.text) `اقرأ محتوى ملف نصي`,
parameters: {
file: zod_1.z.string().min(1).describe("مسار الملف"),
},
implementation: async ({ file }) => {
try {
const path = resolveInsideBase(file);
if (!(0, fs_1.existsSync)(path)) {
return { success: false, error: `الملف غير موجود: ${file}` };
}
const content = await (0, promises_1.readFile)(path, "utf-8");
return { success: true, content, size: content.length };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 3. الإضافة إلى ملف ──
tools.push((0, sdk_1.tool)({
name: "appendToFile",
description: (0, sdk_1.text) `📝 أضف محتوى إلى نهاية ملف (ينشئ الملف إذا لم يكن موجوداً)`,
parameters: {
filePath: zod_1.z.string().min(1).describe("مسار الملف"),
content: zod_1.z.string().min(1).describe("المحتوى المراد إضافته"),
createIfNotExists: zod_1.z.boolean().default(true).describe("إنشاء الملف إذا لم يكن موجوداً"),
addNewLine: zod_1.z.boolean().default(true).describe("إضافة سطر جديد قبل المحتوى"),
},
implementation: async ({ filePath, content, createIfNotExists, addNewLine }) => {
try {
const fullPath = resolveInsideBase(filePath);
const exists = await (0, promises_1.access)(fullPath).then(() => true).catch(() => false);
if (!exists && !createIfNotExists) {
return {
success: false,
error: `الملف غير موجود: ${filePath}`,
hint: "استخدم createIfNotExists=true لإنشائه"
};
}
let contentToAppend = content;
if (addNewLine !== false) {
contentToAppend = "\n" + contentToAppend;
}
await ensureDirectory((0, path_1.dirname)(fullPath));
await (0, promises_1.appendFile)(fullPath, contentToAppend, "utf-8");
return {
success: true,
message: `تمت إضافة ${content.length} حرف إلى ${filePath}`,
created: !exists
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 4. البحث في الملفات ──
tools.push((0, sdk_1.tool)({
name: "find",
description: (0, sdk_1.text) `🔍 ابحث عن نصوص في الملفات (يدعم Regex)`,
parameters: {
searchPath: zod_1.z.string().min(1).describe("المسار للبحث فيه"),
pattern: zod_1.z.string().min(1).describe("النمط للبحث عنه (نص أو Regex)"),
fileTypes: zod_1.z.array(zod_1.z.string()).optional().describe("أنواع الملفات للبحث فيها (مثل .ts, .js)"),
maxDepth: zod_1.z.number().int().min(1).max(10).default(5),
maxResults: zod_1.z.number().int().min(1).max(50).default(20),
},
implementation: async ({ searchPath, pattern, fileTypes, maxDepth, maxResults }) => {
const results = [];
let scanned = 0;
const regex = new RegExp(pattern, "i");
const excludeDirs = [
"node_modules", ".git", "dist", "build", "__pycache__",
".venv", "venv", "env", "temp", "tmp"
];
const textExtensions = [
".txt", ".md", ".js", ".jsx", ".ts", ".tsx", ".py",
".json", ".html", ".css", ".csv", ".xml", ".yml",
".yaml", ".sh", ".bash", ".vue", ".svelte", ".go",
".rs", ".rb", ".php"
];
async function scan(dir, depth = 0) {
if (depth > (maxDepth || 5) || results.length >= (maxResults || 50))
return;
try {
const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
for (const entry of entries) {
if (excludeDirs.includes(entry.name))
continue;
const fullPath = (0, path_1.join)(dir, entry.name);
try {
if (entry.isDirectory()) {
await scan(fullPath, depth + 1);
}
else {
const ext = (0, path_1.extname)(entry.name).toLowerCase();
if (fileTypes && !fileTypes.includes(ext))
continue;
if (!textExtensions.includes(ext) && !fileTypes)
continue;
scanned++;
try {
const content = await (0, promises_1.readFile)(fullPath, "utf-8");
const matches = content.match(regex);
if (matches) {
const lines = content.split("\n");
const lineNum = lines.findIndex((line) => regex.test(line)) + 1;
results.push({
file: entry.name,
path: fullPath,
matches: matches.length,
line: lineNum,
preview: lines[lineNum - 1]?.trim().slice(0, 100) || "",
});
}
}
catch { /* skip binary files */ }
}
}
catch { /* skip */ }
if (results.length >= (maxResults || 50))
return;
}
}
catch { /* skip */ }
}
try {
const basePath = resolveInsideBase(searchPath);
if (!(0, fs_1.existsSync)(basePath)) {
return { success: false, error: `المسار غير موجود: ${searchPath}` };
}
await scan(basePath);
return {
success: true,
pattern,
results: results.slice(0, maxResults || 50),
total: results.length,
scanned,
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 5. إرسال بريد ──
tools.push((0, sdk_1.tool)({
name: "sendEmail",
description: (0, sdk_1.text) `✉️ إرسال بريد إلكتروني عبر SMTP`,
parameters: {
to: zod_1.z.string().email().describe("البريد المستلم"),
subject: zod_1.z.string().min(1).describe("عنوان البريد"),
text: zod_1.z.string().optional().describe("نص البريد"),
html: zod_1.z.string().optional().describe("نص البريد بتنسيق HTML"),
},
implementation: async ({ to, subject, text, html }) => {
try {
const response = await fetch("http://localhost:3007/sendEmail", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ to, subject, text, html }),
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
const result = await response.json();
return { success: true, ...result, system_note: `✉️ تم إرسال البريد إلى ${to}` };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 6. قراءة البريد ──
tools.push((0, sdk_1.tool)({
name: "fetchEmails",
description: (0, sdk_1.text) `📥 قراءة البريد الإلكتروني عبر IMAP`,
parameters: {
limit: zod_1.z.number().int().min(1).max(50).default(10),
unreadOnly: zod_1.z.boolean().default(false),
},
implementation: async ({ limit, unreadOnly }) => {
try {
const response = await fetch("http://localhost:3007/fetchEmails", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ limit, unreadOnly }),
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
const result = await response.json();
return {
success: true,
...result,
system_note: `📥 تم قراءة ${result.emails?.length || 0} بريداً`
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 7. البحث على الإنترنت (مستقل) ──
tools.push((0, sdk_1.tool)({
name: "searchWeb",
description: (0, sdk_1.text) `🌐 البحث على الإنترنت باستخدام Google News`,
parameters: {
query: zod_1.z.string().min(1).describe("نص البحث"),
maxResults: zod_1.z.number().int().min(1).max(20).default(5),
},
implementation: searchWebTool,
}));
// ── 8. تحميل المقالات (مستقل) ──
tools.push((0, sdk_1.tool)({
name: "fetchArticle",
description: (0, sdk_1.text) `📥 تحميل مقال من الإنترنت وحفظه في ملف Markdown`,
parameters: {
url: zod_1.z.string().url().describe("رابط المقال للتحميل"),
filename: zod_1.z.string().optional().describe("اسم الملف (اختياري)"),
},
implementation: fetchArticleTool,
}));
return tools;
}
//# sourceMappingURL=toolsProvider.js.mapdist / toolsProvider.js
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.toolsProvider = toolsProvider;
// src/toolsProvider.ts
const sdk_1 = require("@lmstudio/sdk");
const zod_1 = require("zod");
const promises_1 = require("fs/promises");
const path_1 = require("path");
const fs_1 = require("fs");
const findLMStudioHome_js_1 = require("./findLMStudioHome.js");
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 1. الثوابت والمسارات
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
const LMSTUDIO_HOME = (0, findLMStudioHome_js_1.findLMStudioHome)();
const targetBase = process.env.DEEPEDITOR_BASE || (0, path_1.normalize)("D:\\bido");
function resolveInsideBase(rel) {
const isAbs = /^([A-Za-z]:)?[\\\/]/.test(rel);
return (0, path_1.normalize)(isAbs ? rel : (0, path_1.join)(targetBase, rel));
}
async function ensureDirectory(dirPath) {
if (!(0, fs_1.existsSync)(dirPath))
await (0, promises_1.mkdir)(dirPath, { recursive: true });
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 2. دوال الأدوات المستقلة
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// ── أداة البحث على الإنترنت (مستقلة) ──
async function searchWebTool(params) {
try {
// استيراد serpapi ديناميكياً (لتفادي مشاكل التحميل)
const { getJson } = await Promise.resolve().then(() => __importStar(require('serpapi')));
const API_KEY = 'cd86d518973b79f8e6600672666bff94c590e4b0d2f50be247a2659c03ec1b62';
console.log('🔍 جاري البحث عن: "' + params.query + '" عبر SerpAPI...');
const response = await getJson({
engine: 'google_news',
api_key: API_KEY,
q: params.query,
hl: 'ar',
gl: 'eg',
num: params.maxResults || 5
});
let results = [];
if (response.news_results && response.news_results.length > 0) {
for (let i = 0; i < response.news_results.length && i < (params.maxResults || 5); i++) {
const item = response.news_results[i];
if (!item.link || item.link === '#')
continue;
let source = 'Google News';
if (item.source) {
if (typeof item.source === 'string')
source = item.source;
else if (item.source.name)
source = item.source.name;
}
let snippet = item.snippet || item.description || item.summary || '';
if (typeof snippet !== 'string')
snippet = JSON.stringify(snippet);
if (!snippet || snippet === 'لا يوجد وصف' || snippet.trim() === '') {
snippet = item.title || 'لا يوجد وصف';
}
let published = item.date || new Date().toISOString();
if (typeof published !== 'string')
published = JSON.stringify(published);
let title = item.title || 'بدون عنوان';
title = title.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
results.push({ title, url: item.link, snippet, source, published });
}
}
// إذا لم تكن هناك نتائج عربية، جرب الإنجليزية
if (results.length === 0) {
console.log('⚠️ لا توجد نتائج عربية، جاري البحث بالإنجليزية...');
const cleanQuery = params.query.replace(/[^\w\s]/g, '').trim();
const englishResponse = await getJson({
engine: 'google_news',
api_key: API_KEY,
q: cleanQuery || 'artificial intelligence',
hl: 'en',
gl: 'us',
num: params.maxResults || 5
});
if (englishResponse.news_results) {
for (let j = 0; j < englishResponse.news_results.length && j < (params.maxResults || 5); j++) {
const item = englishResponse.news_results[j];
if (!item.link || item.link === '#')
continue;
let source = 'Google News';
if (item.source) {
if (typeof item.source === 'string')
source = item.source;
else if (item.source.name)
source = item.source.name;
}
let snippet = item.snippet || item.description || item.summary || '';
if (typeof snippet !== 'string')
snippet = JSON.stringify(snippet);
if (!snippet || snippet === 'لا يوجد وصف' || snippet.trim() === '') {
snippet = item.title || 'لا يوجد وصف';
}
let published = item.date || new Date().toISOString();
if (typeof published !== 'string')
published = JSON.stringify(published);
let title = item.title || 'بدون عنوان';
title = title.replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
results.push({ title, url: item.link, snippet, source, published });
}
}
}
if (results.length === 0) {
return {
success: false,
error: 'لم يتم العثور على نتائج',
system_note: '🌐 تم البحث عن "' + params.query + '" في google'
};
}
let displayLines = ['🌐 نتائج البحث عن: ' + params.query];
for (let i = 0; i < results.length; i++) {
const r = results[i];
displayLines.push('\n' + (i + 1) + '. ' + r.title, ' 📰 ' + r.source + ' | 📅 ' + r.published, ' 📄 ' + r.snippet, ' 🔗 ' + r.url);
}
return {
success: true,
results: results,
display: displayLines.join('\n'),
total: results.length,
system_note: '🌐 تم البحث عن "' + params.query + '" في google'
};
}
catch (error) {
console.error('❌ خطأ في البحث:', error.message);
return {
success: false,
error: 'فشل البحث: ' + error.message,
system_note: '⚠️ فشل البحث: ' + error.message
};
}
}
// ── أداة تحميل المقالات (مستقلة) ──
async function fetchArticleTool(params) {
try {
// استيراد node-fetch ديناميكياً
const fetch = (await Promise.resolve().then(() => __importStar(require('node-fetch')))).default;
console.log('📥 جاري تحميل المقال من: ' + params.url);
const response = await fetch(params.url, {
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
const html = await response.text();
// استخراج العنوان
let title = 'بدون عنوان';
const titleMatch = html.match(/<title>(.*?)<\/title>/);
if (titleMatch) {
title = titleMatch[1].replace(/<[^>]*>/g, '').trim();
}
// تنظيف النص
let textContent = html
.replace(/<script[\s\S]*?<\/script>/g, ' ')
.replace(/<style[\s\S]*?<\/style>/g, ' ')
.replace(/<[^>]*>/g, ' ')
.replace(/\s+/g, ' ')
.trim();
// اختصار النص
const maxChars = 5000;
let content = textContent;
if (content.length > maxChars) {
content = content.substring(0, maxChars) + '\n\n... (المقال مختصر)';
}
// إنشاء اسم الملف
const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
const safeTitle = title.replace(/[^a-zA-Z0-9\u0600-\u06FF]/g, '_').slice(0, 50);
const fileName = params.filename || safeTitle + '_' + timestamp;
const saveDir = (0, path_1.join)(targetBase, 'internet_search_results');
if (!(0, fs_1.existsSync)(saveDir)) {
(0, fs_1.mkdirSync)(saveDir, { recursive: true });
}
const filePath = (0, path_1.join)(saveDir, fileName + '.md');
const markdownContent = '# ' + title + '\n\n' +
'**المصدر:** ' + params.url + '\n' +
'**تاريخ التحميل:** ' + new Date().toLocaleString('ar-EG') + '\n\n' +
'---\n\n' +
content;
(0, fs_1.writeFileSync)(filePath, markdownContent, 'utf-8');
console.log('✅ تم حفظ المقال في: ' + filePath);
return {
success: true,
message: '✅ تم حفظ المقال في: ' + filePath,
file: filePath,
title: title,
wordCount: textContent.split(/\s+/).length,
charCount: textContent.length
};
}
catch (error) {
console.error('❌ خطأ في تحميل المقال:', error.message);
return {
success: false,
error: 'فشل تحميل المقال: ' + error.message
};
}
}
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
// 3. التسجيل النهائي في LM Studio
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
async function toolsProvider(ctl) {
const tools = [];
// ── 1. كتابة ملف متقدم ──
tools.push((0, sdk_1.tool)({
name: "writeFileadvanced",
description: (0, sdk_1.text) `اكتب محتوى إلى ملف (ينشئ المجلدات تلقائياً)`,
parameters: {
file: zod_1.z.string().min(1).describe("مسار الملف"),
content: zod_1.z.string().describe("المحتوى المراد كتابته"),
},
implementation: async ({ file, content }) => {
try {
const path = resolveInsideBase(file);
await ensureDirectory((0, path_1.dirname)(path));
await (0, promises_1.writeFile)(path, content, "utf-8");
return { success: true, message: `تم كتابة الملف ${file}` };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 2. قراءة ملف متقدم ──
tools.push((0, sdk_1.tool)({
name: "readFileadvanced",
description: (0, sdk_1.text) `اقرأ محتوى ملف نصي`,
parameters: {
file: zod_1.z.string().min(1).describe("مسار الملف"),
},
implementation: async ({ file }) => {
try {
const path = resolveInsideBase(file);
if (!(0, fs_1.existsSync)(path)) {
return { success: false, error: `الملف غير موجود: ${file}` };
}
const content = await (0, promises_1.readFile)(path, "utf-8");
return { success: true, content, size: content.length };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 3. الإضافة إلى ملف ──
tools.push((0, sdk_1.tool)({
name: "appendToFile",
description: (0, sdk_1.text) `📝 أضف محتوى إلى نهاية ملف (ينشئ الملف إذا لم يكن موجوداً)`,
parameters: {
filePath: zod_1.z.string().min(1).describe("مسار الملف"),
content: zod_1.z.string().min(1).describe("المحتوى المراد إضافته"),
createIfNotExists: zod_1.z.boolean().default(true).describe("إنشاء الملف إذا لم يكن موجوداً"),
addNewLine: zod_1.z.boolean().default(true).describe("إضافة سطر جديد قبل المحتوى"),
},
implementation: async ({ filePath, content, createIfNotExists, addNewLine }) => {
try {
const fullPath = resolveInsideBase(filePath);
const exists = await (0, promises_1.access)(fullPath).then(() => true).catch(() => false);
if (!exists && !createIfNotExists) {
return {
success: false,
error: `الملف غير موجود: ${filePath}`,
hint: "استخدم createIfNotExists=true لإنشائه"
};
}
let contentToAppend = content;
if (addNewLine !== false) {
contentToAppend = "\n" + contentToAppend;
}
await ensureDirectory((0, path_1.dirname)(fullPath));
await (0, promises_1.appendFile)(fullPath, contentToAppend, "utf-8");
return {
success: true,
message: `تمت إضافة ${content.length} حرف إلى ${filePath}`,
created: !exists
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 4. البحث في الملفات ──
tools.push((0, sdk_1.tool)({
name: "find",
description: (0, sdk_1.text) `🔍 ابحث عن نصوص في الملفات (يدعم Regex)`,
parameters: {
searchPath: zod_1.z.string().min(1).describe("المسار للبحث فيه"),
pattern: zod_1.z.string().min(1).describe("النمط للبحث عنه (نص أو Regex)"),
fileTypes: zod_1.z.array(zod_1.z.string()).optional().describe("أنواع الملفات للبحث فيها (مثل .ts, .js)"),
maxDepth: zod_1.z.number().int().min(1).max(10).default(5),
maxResults: zod_1.z.number().int().min(1).max(50).default(20),
},
implementation: async ({ searchPath, pattern, fileTypes, maxDepth, maxResults }) => {
const results = [];
let scanned = 0;
const regex = new RegExp(pattern, "i");
const excludeDirs = [
"node_modules", ".git", "dist", "build", "__pycache__",
".venv", "venv", "env", "temp", "tmp"
];
const textExtensions = [
".txt", ".md", ".js", ".jsx", ".ts", ".tsx", ".py",
".json", ".html", ".css", ".csv", ".xml", ".yml",
".yaml", ".sh", ".bash", ".vue", ".svelte", ".go",
".rs", ".rb", ".php"
];
async function scan(dir, depth = 0) {
if (depth > (maxDepth || 5) || results.length >= (maxResults || 50))
return;
try {
const entries = await (0, promises_1.readdir)(dir, { withFileTypes: true });
for (const entry of entries) {
if (excludeDirs.includes(entry.name))
continue;
const fullPath = (0, path_1.join)(dir, entry.name);
try {
if (entry.isDirectory()) {
await scan(fullPath, depth + 1);
}
else {
const ext = (0, path_1.extname)(entry.name).toLowerCase();
if (fileTypes && !fileTypes.includes(ext))
continue;
if (!textExtensions.includes(ext) && !fileTypes)
continue;
scanned++;
try {
const content = await (0, promises_1.readFile)(fullPath, "utf-8");
const matches = content.match(regex);
if (matches) {
const lines = content.split("\n");
const lineNum = lines.findIndex((line) => regex.test(line)) + 1;
results.push({
file: entry.name,
path: fullPath,
matches: matches.length,
line: lineNum,
preview: lines[lineNum - 1]?.trim().slice(0, 100) || "",
});
}
}
catch { /* skip binary files */ }
}
}
catch { /* skip */ }
if (results.length >= (maxResults || 50))
return;
}
}
catch { /* skip */ }
}
try {
const basePath = resolveInsideBase(searchPath);
if (!(0, fs_1.existsSync)(basePath)) {
return { success: false, error: `المسار غير موجود: ${searchPath}` };
}
await scan(basePath);
return {
success: true,
pattern,
results: results.slice(0, maxResults || 50),
total: results.length,
scanned,
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 5. إرسال بريد ──
tools.push((0, sdk_1.tool)({
name: "sendEmail",
description: (0, sdk_1.text) `✉️ إرسال بريد إلكتروني عبر SMTP`,
parameters: {
to: zod_1.z.string().email().describe("البريد المستلم"),
subject: zod_1.z.string().min(1).describe("عنوان البريد"),
text: zod_1.z.string().optional().describe("نص البريد"),
html: zod_1.z.string().optional().describe("نص البريد بتنسيق HTML"),
},
implementation: async ({ to, subject, text, html }) => {
try {
const response = await fetch("http://localhost:3007/sendEmail", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ to, subject, text, html }),
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
const result = await response.json();
return { success: true, ...result, system_note: `✉️ تم إرسال البريد إلى ${to}` };
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 6. قراءة البريد ──
tools.push((0, sdk_1.tool)({
name: "fetchEmails",
description: (0, sdk_1.text) `📥 قراءة البريد الإلكتروني عبر IMAP`,
parameters: {
limit: zod_1.z.number().int().min(1).max(50).default(10),
unreadOnly: zod_1.z.boolean().default(false),
},
implementation: async ({ limit, unreadOnly }) => {
try {
const response = await fetch("http://localhost:3007/fetchEmails", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ limit, unreadOnly }),
});
if (!response.ok)
throw new Error(`HTTP ${response.status}`);
const result = await response.json();
return {
success: true,
...result,
system_note: `📥 تم قراءة ${result.emails?.length || 0} بريداً`
};
}
catch (error) {
return { success: false, error: error.message };
}
},
}));
// ── 7. البحث على الإنترنت (مستقل) ──
tools.push((0, sdk_1.tool)({
name: "searchWeb",
description: (0, sdk_1.text) `🌐 البحث على الإنترنت باستخدام Google News`,
parameters: {
query: zod_1.z.string().min(1).describe("نص البحث"),
maxResults: zod_1.z.number().int().min(1).max(20).default(5),
},
implementation: searchWebTool,
}));
// ── 8. تحميل المقالات (مستقل) ──
tools.push((0, sdk_1.tool)({
name: "fetchArticle",
description: (0, sdk_1.text) `📥 تحميل مقال من الإنترنت وحفظه في ملف Markdown`,
parameters: {
url: zod_1.z.string().url().describe("رابط المقال للتحميل"),
filename: zod_1.z.string().optional().describe("اسم الملف (اختياري)"),
},
implementation: fetchArticleTool,
}));
return tools;
}
//# sourceMappingURL=toolsProvider.js.map