Project Files
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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toolsProvider = toolsProvider;
// src/toolsProvider.ts
const sdk_1 = require("@lmstudio/sdk");
const child_process_1 = require("child_process");
const promises_1 = require("fs/promises");
const path_1 = require("path");
const zod_1 = require("zod");
const fs_1 = require("fs");
const exceljs_1 = __importDefault(require("exceljs"));
/* ---------- Helper Functions (not registered as tools) ---------- */
async function ensureDirectory(dirPath) {
if (!(0, fs_1.existsSync)(dirPath)) {
await (0, promises_1.mkdir)(dirPath, { recursive: true });
}
}
async function runCommand(options) {
const { cmd, args = [], cwd = process.cwd(), timeoutMs = 0, stageLabel } = options;
return await new Promise((resolve) => {
const child = (0, child_process_1.spawn)(cmd, args, { cwd, stdio: ['ignore', 'pipe', 'pipe'] });
let stdout = '';
let stderr = '';
child.stdout?.on('data', (d) => (stdout += d));
child.stderr?.on('data', (d) => (stderr += d));
let killedByTimeout = false;
let timer;
if (timeoutMs && timeoutMs > 0) {
timer = setTimeout(() => {
killedByTimeout = true;
try {
child.kill();
}
catch { }
}, timeoutMs);
}
child.on('close', async (code) => {
if (timer)
clearTimeout(timer);
const timestamp = new Date().toISOString();
const header = stageLabel ? `--- ${stageLabel} ---` : `--- ${cmd} ${args.join(' ')} ---`;
const logEntry = `\n\n${header} ${timestamp}\nEXIT CODE: ${code}${killedByTimeout ? ' (timeout)' : ''}\nSTDOUT:\n${stdout}\nSTDERR:\n${stderr}\n`;
try {
const logDir = (0, path_1.join)(process.cwd(), 'copilot_unit');
await ensureDirectory(logDir);
await (0, promises_1.writeFile)((0, path_1.join)(logDir, 'execution_trace.md'), logEntry, { flag: 'a' });
}
catch { }
const exitCode = typeof code === 'number' ? code : -1;
resolve({ success: exitCode === 0 && !killedByTimeout, stdout: stdout.trim(), stderr: stderr.trim(), code: exitCode });
});
child.on('error', async (err) => {
if (timer)
clearTimeout(timer);
const timestamp = new Date().toISOString();
const header = stageLabel ? `--- ${stageLabel} ERROR ---` : `--- ${cmd} ERROR ---`;
const logEntry = `\n\n${header} ${timestamp}\nERROR: ${String(err)}\n`;
try {
const logDir = (0, path_1.join)(process.cwd(), 'copilot_unit');
await ensureDirectory(logDir);
await (0, promises_1.writeFile)((0, path_1.join)(logDir, 'execution_trace.md'), logEntry, { flag: 'a' });
}
catch { }
resolve({ success: false, stdout: stdout.trim(), stderr: String(err), code: -1 });
});
});
}
/* ---------- Core File Operations ---------- */
async function toolsProvider(ctl) {
const tools = [];
// وضع غير آمن عبر متغير بيئة لتعطيل القيود
const UNSAFE = ["1", "true", "yes"].includes(String(process.env.COPILOT_UNIT_UNSAFE || "").toLowerCase());
// تثبيت الجذر على مجلد الإضافة: __dirname يشير إلى dist، نأخذ الأب ليكون newtools
const pluginRoot = (0, path_1.normalize)((0, path_1.join)(__dirname, ".."));
// السماح بفرض الجذر عبر متغير بيئة COPILOT_UNIT_BASE إن تم ضبطه
const envBase = (process.env.COPILOT_UNIT_BASE || "").trim();
// مرشحات إضافية اعتماداً على manifest.json
const candidates = [];
try {
const wd = ctl.getWorkingDirectory();
if (wd && wd.trim().length > 0)
candidates.push((0, path_1.normalize)(wd));
}
catch { }
const cwd = (0, path_1.normalize)(process.cwd());
candidates.push(cwd);
candidates.push((0, path_1.normalize)((0, path_1.join)(cwd, "..")));
let projectRoot = envBase ? (0, path_1.normalize)(envBase) : pluginRoot;
const manifestRoot = [pluginRoot, ...candidates].find(p => (0, fs_1.existsSync)((0, path_1.join)(p, "manifest.json")));
if (!envBase && manifestRoot)
projectRoot = manifestRoot;
const targetBase = (0, path_1.join)(projectRoot, "copilot_unit");
await ensureDirectory(targetBase);
/* ----------------- writeFile ----------------- */
tools.push((0, sdk_1.tool)({
name: "writeFile",
description: (0, sdk_1.text) `كتابة أو إنشاء ملف.`,
parameters: { file: zod_1.z.string().min(1), content: zod_1.z.string() },
implementation: async ({ file, content }) => {
const filePath = resolveInsideBase(targetBase, file, UNSAFE);
await ensureDirectory((0, path_1.join)(filePath, ".."));
await (0, promises_1.writeFile)(filePath, content, "utf-8");
return { success: true, message: `تم كتابة الملف ${file}` };
}
}));
/* ----------------- readFile ----------------- */
tools.push((0, sdk_1.tool)({
name: "readFile",
description: (0, sdk_1.text) `قراءة محتوى ملف.`,
parameters: { file: zod_1.z.string().min(1) },
implementation: async ({ file }) => {
const filePath = resolveInsideBase(targetBase, file, UNSAFE);
if (!(0, fs_1.existsSync)(filePath))
return { success: false, error: `الملف ${file} غير موجود.` };
const content = await (0, promises_1.readFile)(filePath, "utf-8");
return { success: true, content };
}
}));
/* ----------------- renameFile (fs.rename) ----------------- */
tools.push((0, sdk_1.tool)({
name: "renameFile",
description: (0, sdk_1.text) `إعادة تسمية ملف.`,
parameters: { oldName: zod_1.z.string().min(1), newName: zod_1.z.string().min(1) },
implementation: async ({ oldName, newName }) => {
const oldPath = resolveInsideBase(targetBase, oldName, UNSAFE);
const newPath = resolveInsideBase(targetBase, newName, UNSAFE);
if (!(0, fs_1.existsSync)(oldPath))
return { success: false, error: `الملف ${oldName} غير موجود.` };
await ensureDirectory((0, path_1.join)(newPath, ".."));
await (0, promises_1.rename)(oldPath, newPath);
return { success: true, message: `تمت إعادة التسمية إلى ${newName}` };
}
}));
/* ----------------- createFolder ----------------- */
tools.push((0, sdk_1.tool)({
name: "createFolder",
description: (0, sdk_1.text) `إنشاء مجلد.`,
parameters: { folder: zod_1.z.string().min(1) },
implementation: async ({ folder }) => {
const folderPath = resolveInsideBase(targetBase, folder, UNSAFE);
await (0, promises_1.mkdir)(folderPath, { recursive: true });
return { success: true, message: `تم إنشاء المجلد ${folder}` };
}
}));
/* ----------------- deleteFolder ----------------- */
tools.push((0, sdk_1.tool)({
name: "deleteFolder",
description: (0, sdk_1.text) `حذف مجلد.`,
parameters: { folder: zod_1.z.string().min(1) },
implementation: async ({ folder }) => {
const folderPath = resolveInsideBase(targetBase, folder, UNSAFE);
if (!(0, fs_1.existsSync)(folderPath))
return { success: false, error: `المجلد ${folder} غير موجود.` };
await (0, promises_1.rm)(folderPath, { recursive: true, force: true });
return { success: true, message: `تم حذف المجلد ${folder}` };
}
}));
/* ----------------- deleteFile (new tool) ----------------- */
tools.push((0, sdk_1.tool)({
name: "deleteFile",
description: (0, sdk_1.text) `حذف ملف معين.`,
parameters: { file: zod_1.z.string().min(1) },
implementation: async ({ file }) => {
const filePath = resolveInsideBase(targetBase, file, UNSAFE);
if (!(0, fs_1.existsSync)(filePath))
return { success: false, error: `الملف ${file} غير موجود.` };
await (0, promises_1.rm)(filePath, { force: true });
return { success: true, message: `تم حذف الملف ${file}` };
}
}));
/* ----------------- getCurrentTime (new tool) ----------------- */
tools.push((0, sdk_1.tool)({
name: "getCurrentTime",
description: (0, sdk_1.text) `إحضار الوقت الحالي بالتنسيق المحلي.`,
parameters: {},
implementation: async () => {
const now = new Date();
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC";
return { success: true, time: now.toLocaleTimeString(), iso: now.toISOString(), timezone };
}
}));
/* ----------------- getCurrentDate (new tool) ----------------- */
tools.push((0, sdk_1.tool)({
name: "getCurrentDate",
description: (0, sdk_1.text) `إحضار التاريخ الحالي بالتنسيق المحلي.`,
parameters: {},
implementation: async () => {
const today = new Date();
const isoDate = today.toISOString().slice(0, 10);
return { success: true, date: today.toLocaleDateString(), isoDate };
}
}));
/* ----------------- listDirectoryStructure (new tool) ----------------- */
tools.push((0, sdk_1.tool)({
name: "listDirectoryStructure",
description: (0, sdk_1.text) `عرض بنية مجلد العمل مع أسماء الملفات والمجلدات وأحجامها.`,
parameters: { folder: zod_1.z.string().default("") },
implementation: async ({ folder }) => {
const dirPath = resolveInsideBase(targetBase, folder || "");
if (!(0, fs_1.existsSync)(dirPath))
return { success: false, error: `المجلد ${folder || "[الجذر]"} غير موجود.` };
const { readdir, stat } = await Promise.resolve().then(() => __importStar(require("fs/promises")));
const entries = await readdir(dirPath, { withFileTypes: true });
const structure = await Promise.all(entries.map(async (entry) => {
const fullPath = (0, path_1.join)(dirPath, entry.name);
const stats = await stat(fullPath);
return {
name: entry.name,
type: entry.isDirectory() ? "مجلد" : "ملف",
size: entry.isDirectory() ? "-" : `${(stats.size / 1024).toFixed(2)} KB`,
modified: stats.mtime.toISOString()
};
}));
return { success: true, folder: folder || "[الجذر]", items: structure };
}
}));
/* ----------------- summarizeWithModel (existing) ----------------- */
tools.push((0, sdk_1.tool)({
name: "summarizeWithModel",
description: (0, sdk_1.text) `تلخيص إدراكي باستخدام النموذج.`,
parameters: { filename: zod_1.z.string().min(1).regex(/^[^\/\\$+]+$/) },
implementation: async ({ filename }) => {
const filePath = resolveInsideBase(targetBase, filename.endsWith(".txt") ? filename : `${filename}.txt`);
if (!(0, fs_1.existsSync)(filePath))
return { success: false, error: `الملف ${filename} غير موجود.` };
const content = await (0, promises_1.readFile)(filePath, "utf-8");
const summary = content
.split(/\n+/)
.slice(0, 3)
.join(" ")
.slice(0, 2000);
return { success: true, summary };
}
}));
/* ----------------- markAwareness (existing) ----------------- */
tools.push((0, sdk_1.tool)({
name: "markAwareness",
description: (0, sdk_1.text) `توثيق لحظة إدراك.`,
parameters: { insight: zod_1.z.string().min(10) },
implementation: async ({ insight }) => {
const filePath = (0, path_1.join)(targetBase, "model_reflection.md");
const entry = `\n### لحظة إدراك\n- ${new Date().toISOString()}\n- ${insight}\n`;
await (0, promises_1.writeFile)(filePath, entry, { flag: "a" });
return { success: true, message: "تم تسجيل الإدراك." };
}
}));
/* ----------------- suggestNextAction (existing) ----------------- */
tools.push((0, sdk_1.tool)({
name: "suggestNextAction",
description: (0, sdk_1.text) `اقتراح خطوة إدراكية تالية.`,
parameters: { last_tool: zod_1.z.string().min(1), context: zod_1.z.string().min(5) },
implementation: async ({ last_tool, context }) => {
let suggestion = "لا يوجد اقتراح واضح.";
if (last_tool === "summarizeWithModel") {
suggestion = "هل ترغب في تسجيل هذا التلخيص في سجل الإدراك؟";
}
const timestamp = new Date().toISOString();
const entry = `\n\n--- ${timestamp} ---\nالأداة السابقة: ${last_tool}\nالسياق: ${context}\nالاقتراح: ${suggestion}\n`;
const filePath = (0, path_1.join)(targetBase, "next_action_suggestions.md");
await (0, promises_1.writeFile)(filePath, entry, { flag: "a" });
return { success: true, suggestion, path: filePath, timestamp };
}
}));
/* ----------------- generateTrace (existing) ----------------- */
tools.push((0, sdk_1.tool)({
name: "generateTrace",
description: (0, sdk_1.text) `توليد سجل تنفيذ حيّ.`,
parameters: { input: zod_1.z.string().min(5) },
implementation: async ({ input }) => {
const tracePath = (0, path_1.join)(targetBase, "execution_trace.md");
const timestamp = new Date().toISOString();
const entry = `\n\n--- ${timestamp} ---\n${input}\n`;
await (0, promises_1.writeFile)(tracePath, entry, { flag: 'a' });
return { success: true, message: "تم حفظ السجل", path: tracePath };
}
}));
/* ----------------- logToolUsage (existing) ----------------- */
tools.push((0, sdk_1.tool)({
name: "logToolUsage",
description: (0, sdk_1.text) `تسجيل استخدام أداة في tool_log.md.`,
parameters: {
tool_name: zod_1.z.string().min(1),
context: zod_1.z.string().min(5)
},
implementation: async ({ tool_name, context }) => {
const logPath = (0, path_1.join)(targetBase, "tool_log.md");
const timestamp = new Date().toISOString();
const entry = `\n\n--- ${timestamp} ---\nأداة: ${tool_name}\n${context}\n`;
await (0, promises_1.writeFile)(logPath, entry, { flag: 'a' });
return { success: true, message: "تم تسجيل استخدام الأداة", path: logPath };
}
}));
/* ----------------- exportTextFile (external function) ----------------- */
tools.push((0, sdk_1.tool)({
name: "exportTextFile",
description: (0, sdk_1.text) `تصدير ملف نصي باستخدام الدالة الخارجية.`,
parameters: { filename: zod_1.z.string().min(1), content: zod_1.z.string() },
implementation: async ({ filename, content }) => {
const filePath = resolveInsideBase(targetBase, filename.endsWith(".txt") ? filename : `${filename}.txt`);
await ensureDirectory((0, path_1.join)(filePath, ".."));
await (0, promises_1.writeFile)(filePath, content, "utf-8");
return { success: true, message: `تم تصدير الملف ${filename}` };
}
}));
/* ----------------- saveContextMemory ----------------- */
tools.push((0, sdk_1.tool)({
name: "saveContextMemory",
description: (0, sdk_1.text) `حفظ إدخالات ذاكرة سياقية في ملف JSON هرمي داخل copilot_unit/memory/`,
parameters: {
namespace: zod_1.z.string().min(1).default("default"),
entry: zod_1.z.object({
role: zod_1.z.string().default("system"),
content: zod_1.z.string().min(1),
tags: zod_1.z.array(zod_1.z.string()).default([]),
metadata: zod_1.z.record(zod_1.z.any()).default({})
})
},
implementation: async ({ namespace, entry }) => {
const memDir = resolveInsideBase(targetBase, (0, path_1.join)("memory", namespace));
await (0, promises_1.mkdir)(memDir, { recursive: true });
const memPath = (0, path_1.join)(memDir, "context_memory.json");
const prev = (0, fs_1.existsSync)(memPath) ? JSON.parse(await (0, promises_1.readFile)(memPath, "utf-8")) : { entries: [] };
const record = { id: Date.now().toString(36), timestamp: new Date().toISOString(), ...entry };
prev.entries.push(record);
await (0, promises_1.writeFile)(memPath, JSON.stringify(prev, null, 2), "utf-8");
return { success: true, path: memPath, count: prev.entries.length };
}
}));
/* ----------------- loadContextMemory ----------------- */
tools.push((0, sdk_1.tool)({
name: "loadContextMemory",
description: (0, sdk_1.text) `تحميل إدخالات الذاكرة السياقية من copilot_unit/memory/ مع مرشح اختياري بالعلامات`,
parameters: {
namespace: zod_1.z.string().min(1).default("default"),
tag: zod_1.z.string().optional()
},
implementation: async ({ namespace, tag }) => {
const memDir = resolveInsideBase(targetBase, (0, path_1.join)("memory", namespace));
const memPath = (0, path_1.join)(memDir, "context_memory.json");
if (!(0, fs_1.existsSync)(memPath))
return { success: true, entries: [] };
const data = JSON.parse(await (0, promises_1.readFile)(memPath, "utf-8"));
const entries = Array.isArray(data.entries) ? data.entries : [];
const filtered = tag ? entries.filter((e) => Array.isArray(e.tags) && e.tags.includes(tag)) : entries;
return { success: true, entries: filtered };
}
}));
tools.push((0, sdk_1.tool)({
name: "readExcelSheet",
description: (0, sdk_1.text) `قراءة ورقة من ملف إكسيل داخل copilot_unit`,
parameters: {
file: zod_1.z.string().min(1),
sheet: zod_1.z.string().optional()
},
implementation: async ({ file, sheet }) => {
const filePath = resolveInsideBase(targetBase, file.endsWith('.xlsx') ? file : `${file}.xlsx`);
const wb = new exceljs_1.default.Workbook();
if (!(0, fs_1.existsSync)(filePath)) {
return { success: false, error: `الملف غير موجود: ${file}` };
}
await wb.xlsx.readFile(filePath);
const ws = sheet ? wb.getWorksheet(sheet) : wb.worksheets[0];
if (!ws)
return { success: false, error: `لا توجد ورقة مطابقة` };
const rows = [];
ws.eachRow((row) => {
const vals = [];
row.eachCell({ includeEmpty: true }, (cell) => {
vals.push(cell.value);
});
rows.push(vals);
});
return { success: true, rows, sheet: ws.name };
}
}));
tools.push((0, sdk_1.tool)({
name: "appendExcelRow",
description: (0, sdk_1.text) `إضافة صف إلى ورقة إكسيل (إنشاء الملف/الورقة إن لم توجد)`,
parameters: {
file: zod_1.z.string().min(1),
sheet: zod_1.z.string().optional(),
row: zod_1.z.array(zod_1.z.union([zod_1.z.string(), zod_1.z.number(), zod_1.z.boolean()])).min(1)
},
implementation: async ({ file, sheet, row }) => {
const filePath = resolveInsideBase(targetBase, file.endsWith('.xlsx') ? file : `${file}.xlsx`);
const wb = new exceljs_1.default.Workbook();
if ((0, fs_1.existsSync)(filePath)) {
await wb.xlsx.readFile(filePath);
}
let ws = sheet ? wb.getWorksheet(sheet) : wb.worksheets[0];
if (!ws) {
ws = wb.addWorksheet(sheet || 'Sheet1');
}
ws.addRow(row);
await ensureDirectory((0, path_1.dirname)(filePath));
await wb.xlsx.writeFile(filePath);
return { success: true, message: `تمت إضافة صف إلى ${ws.name}`, path: filePath };
}
}));
tools.push((0, sdk_1.tool)({
name: "runJavaScript",
description: (0, sdk_1.text) `تنفيذ JavaScript عبر Node.js من نص أو ملف`,
parameters: {
code: zod_1.z.string().optional(),
file: zod_1.z.string().optional(),
args: zod_1.z.array(zod_1.z.string()).optional(),
timeoutMs: zod_1.z.number().int().min(0).max(300000).optional()
},
implementation: async ({ code, file, args, timeoutMs }) => {
const argv = Array.isArray(args) ? args : [];
let scriptPath;
let cwd = targetBase;
if (file && file.trim().length > 0) {
scriptPath = resolveInsideBase(targetBase, file, UNSAFE);
if (!(0, fs_1.existsSync)(scriptPath)) {
return { success: false, error: `الملف غير موجود: ${file}` };
}
cwd = (0, path_1.dirname)(scriptPath);
}
else if (code && code.trim().length > 0) {
// اكتب الكود إلى ملف مؤقت داخل copilot_unit/scripts لتفادي مشاكل الاقتباس في -e
const scriptsDir = (0, path_1.join)(targetBase, "scripts");
await ensureDirectory(scriptsDir);
scriptPath = (0, path_1.join)(scriptsDir, `run_tmp_${Date.now()}.js`);
await (0, promises_1.writeFile)(scriptPath, code, "utf-8");
cwd = scriptsDir;
}
else {
return { success: false, error: "يجب توفير إما code أو file" };
}
const res = await runCommand({
cmd: process.platform === "win32" ? "node" : "node",
args: scriptPath ? [scriptPath, ...argv] : [],
cwd,
timeoutMs,
stageLabel: "runJavaScript"
});
return {
success: !!res.success,
code: res.code,
stdout: res.stdout,
stderr: res.stderr,
cwd,
script: scriptPath
};
}
}));
return tools;
}
/* ---------- Helper Functions (not registered as tools) ---------- */
function resolveInsideBase(baseDir, rel, unsafe = false) {
if (unsafe) {
const isAbs = /^([A-Za-z]:)?[\\/]/.test(rel);
return (0, path_1.normalize)(isAbs ? rel : (0, path_1.join)(baseDir, rel || ""));
}
const baseNorm = (0, path_1.normalize)(baseDir);
const target = (0, path_1.normalize)((0, path_1.join)(baseDir, rel || ""));
const b = baseNorm.toLowerCase();
const r = target.toLowerCase();
const bSep = b.endsWith("\\") || b.endsWith("/") ? b : b + "\\";
const inside = r === b || r.startsWith(bSep);
if (!inside) {
throw new Error("مسار غير مسموح: خروج خارج copilot_unit");
}
return target;
}
//# sourceMappingURL=toolsProvider.js.map