// دليل المطور

مستندات مطور البرنامج المساعد

أنشئ مكونات إضافية لتطبيق سطح المكتب AnBoWork: أضف أدوات جديدة للذكاء الاصطناعي، وقم بإرساء اللوحة الخاصة بك بجوار الجلسة، وأرسل إشعارات النظام، وقم بتحليل تنسيقات الملفات الجديدة. يكفي وجود ملفmani.json واحد بالإضافة إلى نص إدخال واحد للبدء.

01ملخص

البرنامج المساعد AnBoWork هو برنامج Node.js عادي. بعد التثبيت، يقوم التطبيق بتقسيمها كعملية فرعية مستقلة (عقدة خالصة، بدون واجهة برمجة تطبيقات إلكترونية) ويتحدث إليها عبر رسائل بين العمليات. لا توجد حزمة SDK مطلوبة؛ كل ما تحتاجه هو process.on('message') وprocess.send().

يتم الإعلان عن كل ما يمكن للمكون الإضافي القيام به بشكل ثابت في manifest.json: يمكن لصفحة موافقة التثبيت المسبق ومراجعة السوق معرفة الأدوات التي يضيفها والأذونات التي يحتاجها دون تشغيل أي كود إضافي. يتم عرض كافة واجهات المستخدم (أيقونات شريط الأدوات، والإعدادات، ولوحة الأوامر، وقوائم السياق) بواسطة المضيف من الإعلان؛ لا يعمل رمز البرنامج المساعد أبدًا داخل النافذة الرئيسية. تعتبر العروض المثبتة واللوحات العائمة هي لغة HTML الخاصة بك فقط، ويتم تشغيلها في صفحات معزولة في وضع الحماية.

القدرات في لمحة

المجال الظاهرالقدرةحيث يرى المستخدمون ذلك
toolsأضف أدوات قابلة للاستدعاء للذكاء الاصطناعييقوم الذكاء الاصطناعي بالاتصال بهم تلقائيًا أثناء المحادثة؛ يتم عرض استدعاءات الأداة في الجلسة
viewsيتم إرساء العرض المستمر في الشريط الجانبي الأيمن للجلسةيفتح رمز إضافي في شريط أدوات الجلسة صفحتك على اليمين
uiنافذة عائمة مستقلةيتم فتحه من القائمة "⋯" في قائمة المكونات الإضافية
sessionActionرمز الإجراء المستمر في شريط أدوات الجلسةبنقرة واحدة يتم تشغيل الأداة التي تحددها
configurationالإدخالات في صفحة الإعداداتالإعدادات → تكوين البرنامج المساعد. يتم تمرير القيم مع كل مكالمة
commandsإدخالات لوحة الأوامر Ctrl/Cmd+Kلوحة الأوامر
keybindingsاختصارات لوحة المفاتيح العالميةتؤدي مجموعة المفاتيح إلى تشغيل أمر
menusعناصر قائمة سياق الجلسةقائمة "⋯" / النقر بزر الماوس الأيمن في صف الجلسة
documentParsersتم إسقاط ملفات التحليل في مربع الإدخاليتم استدعاؤه تلقائيًا عندما يسقط المستخدم ملفًا مطابقًا
activationEventsابدأ مع التطبيقخفي؛ للمكونات الإضافية التي تحتاج إلى مؤقتات في الخلفية
permissionsأعلن الأذونات المطلوبةصفحة موافقة التثبيت المسبق

02بداية سريعة

يحتاج البرنامج الإضافي البسيط إلى ملفين فقط.

my-plugin/
├── manifest.json   # plugin manifest (required)
├── index.js        # entry script, referenced by manifest.main (required)
├── view.html       # docked view page (optional, manifest.views[].entry)
└── ui.html         # floating panel page (optional, manifest.ui.entry)

1. اكتب البيان.json

{
  "id": "com.example.hello",
  "name": "Hello Plugin",
  "version": "1.0.0",
  "description": "Say hello to the user.",
  "main": "index.js",
  "permissions": [],
  "tools": [
    {
      "name": "say_hello",
      "summary": "Greet the user by name",
      "description": "Return a greeting for the given name. Call this when the user explicitly asks the plugin to say hello.",
      "parameters": {
        "type": "object",
        "properties": {
          "name": { "type": "string", "description": "Who to greet." }
        },
        "required": ["name"]
      }
    }
  ]
}

2. اكتب نص الدخول

// The entry script runs in a standalone Node.js child process (ELECTRON_RUN_AS_NODE=1).
// Only Node built-ins and dependencies shipped inside the plugin folder are available;
// there is no Electron API.
process.on('message', (msg) => {
  if (!msg || msg.type !== 'call_tool') return;
  const { requestId, toolName, params } = msg;
  try {
    if (toolName !== 'say_hello') throw new Error(`unknown tool: ${toolName}`);
    process.send({
      type: 'tool_result',
      requestId,
      content: [{ type: 'text', text: `Hello, ${params.name}!` }],
    });
  } catch (err) {
    process.send({ type: 'tool_error', requestId, message: err.message });
  }
});

3. قم بالتثبيت في التطبيق

افتح AnBoWork ← الشريط العلوي "الأدوات" ← "المكونات الإضافية" ← "التثبيت محليًا" في الزاوية العلوية اليمنى، ثم اختر مجلد البرنامج الإضافي (أو ملف مضغوط منه). تسرد صفحة الموافقة الأذونات المعلنة وكل أداة قبل التثبيت؛ تأكيد للتمكين.

4. جربه

في أي جلسة، أخبر الذكاء الاصطناعي "اطلب من المكون الإضافي أن يلقي التحية على أليس". بناءً على وصف الأداة، يقرر الذكاء الاصطناعي الاتصال بالرقم say_hello، وتظهر المكالمة ونتيجتها في الجلسة.

نصيحة
يمكن للذكاء الاصطناعي الموجود داخل AnBoWork أيضًا إنشاء مكونات إضافية لك (قل "اكتب لي مكونًا إضافيًا يفعل X" وسيستدعي create_local_plugin). يتم تعطيل المكونات الإضافية التي تم إنشاؤها بشكل افتراضي حتى تقوم بمراجعة الكود الموجود على صفحة المكونات الإضافية وتمكينها يدويًا. ينطبق هذا الدليل بالتساوي على قراءة وتعديل المكونات الإضافية التي تم إنشاؤها بواسطة الذكاء الاصطناعي.

03الحقول الظاهرة

مجاليكتبمطلوبوصف
idstringنعمنمط المجال العكسي، على سبيل المثال com.example.my-plugin. الحروف والأرقام والنقاط والواصلات فقط. غير قابل للتغيير بمجرد إنشائه؛ يتم التعامل مع تثبيت نفس المعرف مرة أخرى على أنه إعادة تثبيت.
namestringنعماسم البرنامج المساعد. يتم إدخاله مع description إلى النموذج كسياق، لذا يوصى باللغة الإنجليزية.
versionstringنعمالنسخة الدلالية. يستخدمه السوق للكشف عن التحديثات.
descriptionstringنعمجملة واحدة تصف ما يفعله البرنامج المساعد (باللغة الإنجليزية).
authorstringلامؤلف.
readmestringلاالوصف الطويل الموضح في صفحة تفاصيل السوق، يدعم Markdown. يجب أن تكون الصور الموجودة بداخله https عناوين URL — المسارات النسبية للملفات المجمعة في ملف مضغوط غير مدعومة.
iconstringلاالأيقونة المعروضة في قائمة السوق وصفحة التفاصيل — مسار نسبي لملف مجمع في ملف مضغوط (على سبيل المثال icon.png). يجب أن يكون PNG وليس SVG، وبحجم 128×128 على الأقل.
mainstringنعمنص الإدخال، نسبة إلى مجلد البرنامج المساعد. .. لا يسمح بالهروب من المجلد.
permissionsstring[]نعمnetwork / filesystem / notifications; قد تكون مصفوفة فارغة. راجع "نموذج الإذن".
toolsobject[]نعمإعلانات الأداة؛ قد تكون مصفوفة فارغة. راجع "الأدوات وبروتوكول الاتصال".
documentParsersobject[]لاالقدرة على تحليل الملف.
uiobjectلالوحة عائمة:{ entry, title }
viewsobject[]لاطرق العرض الراسية:{ id, title, icon, entry, width? }
sessionActionobjectلارمز شريط الأدوات، رمز واحد على الأكثر لكل مكون إضافي.
configurationobject[]لاقائمة إدخالات الإعدادات.
commandsobject[]لاإدخالات لوحة الأوامر.
keybindingsobject[]لاالاختصارات. command يجب أن يشير إلى tool للإدخال في commands[]، وإلا فسيتم رفض التثبيت.
menusobjectلاالموقع session/context فقط متاح في الوقت الحالي.
activationEventsstring[]لافقط onStartupFinished في الوقت الحالي.

الاتفاقيات اللغوية للنص

النص الموجود في البيان له جمهوران. للموديل: name, description, tools[].description, tools[].parameters.*.description. اكتب هذه باللغة الإنجليزية؛ تفهم النماذج أوصاف الأدوات باللغة الإنجليزية وتملأ المعلمات بشكل أكثر موثوقية. للأشخاص: tools[].summary (ملخص من سطر واحد في صفحة الموافقة)، ui.title، views[].title، sessionAction.tooltip، configuration[].label، commands[].title وtitle بالداخل menus. اكتبها بلغة المستخدمين المستهدفين.

{
  "id": "com.example.full",
  "name": "Full Example",
  "version": "1.2.0",
  "description": "Every contribution point in one manifest.",
  "author": "Example Inc.",
  "readme": "## Full Example\n\nLonger Markdown shown on the marketplace detail page. Images must be https URLs.",
  "icon": "icon.png",
  "main": "index.js",
  "permissions": ["filesystem", "network", "notifications"],
  "activationEvents": ["onStartupFinished"],
  "tools": [
    {
      "name": "do_something",
      "summary": "Do one thing to the current project",
      "description": "…English. State clearly when to call this and when not to…",
      "parameters": { "type": "object", "properties": {}, "required": [] },
      "renderAs": "checklist"
    },
    { "name": "is_available", "summary": "Whether the current folder applies", "description": "…", "parameters": { "type": "object", "properties": {} } },
    { "name": "list_modes", "summary": "List selectable modes", "description": "…", "parameters": { "type": "object", "properties": {} } }
  ],
  "documentParsers": [
    { "mimeType": "text/markdown", "toolName": "parse_markdown" }
  ],
  "ui": { "entry": "ui.html", "title": "Example Panel" },
  "views": [
    { "id": "board", "title": "Example Board", "icon": "checklist", "entry": "view.html", "width": 380 }
  ],
  "sessionAction": {
    "tool": "do_something",
    "icon": "git-branch",
    "tooltip": "Do one thing to the current project",
    "visibleTool": "is_available"
  },
  "configuration": [
    { "id": "mode", "label": "Mode", "type": "select", "optionsTool": "list_modes", "defaultValue": "auto" },
    { "id": "verbose", "label": "Verbose output", "type": "boolean", "defaultValue": false },
    { "id": "prefix", "label": "Prefix", "type": "string", "defaultValue": "" },
    { "id": "limit", "label": "Max items", "type": "number", "defaultValue": 20 }
  ],
  "commands": [
    { "tool": "do_something", "icon": "git-branch", "title": "Do one thing to the current project" }
  ],
  "keybindings": [
    { "command": "do_something", "key": "mod+shift+d" }
  ],
  "menus": {
    "session/context": [
      { "tool": "do_something", "icon": "git-branch", "title": "Do one thing to this session" }
    ]
  }
}

04نموذج الإذن

permissions يجب أن يعكس بصدق ما يفعله الكود بالفعل. تسرد صفحة الموافقة المسبقة على التثبيت كل واحدة منها حتى يتمكن المستخدمون من تحديد ما إذا كانوا يريدون التثبيت أم لا؛ تقوم مراجعة السوق أيضًا بفحص الإعلان مقابل الكود.

إذنعندما يجب أن يعلنكيف يعاملها المضيف
filesystemقراءة أو كتابة ملفات المستخدم (قراءة كود المشروع، إنشاء المستندات، تخزين البيانات في المجلد الرئيسي)الموافقة المستنيرة، تظهر للمستخدم.
networkإجراء أي طلب للشبكة (واجهات برمجة التطبيقات التابعة لجهات خارجية، والتنزيلات)الموافقة المستنيرة، تظهر للمستخدم.
notificationsعرض إشعارات النظام عبر show_notification RPC العكسيEnforced: الاتصال به بدون الإقرار يعود host_error ولا يظهر أي إشعار.
ملحوظة
عملية البرنامج الفرعي هي بيئة Node.js كاملة. filesystem وnetwork حاليًا عبارة عن إعلانات على مستوى الموافقة، وليست وضع حماية لوقت التشغيل: لا يعترض المضيف fs أو fetch. ولهذا السبب بالتحديد يجب أن تكون التصريحات صادقة. يتم رفض المكونات الإضافية التي لم يتم الإعلان عنها جيدًا في مراجعة السوق وتفقد ثقة المستخدم عند اكتشافها. لا تبالغ في التصريح أيضًا (الأذونات غير المستخدمة تجعل المستخدمين يترددون).

الخصوصية والبيانات

context.cwd هو مجلد مشروع المستخدم وقد يحتوي على كود المصدر وتكوين حساس؛ قد تحتوي وسائط الأداة على محادثة المستخدم. لا ترسل هذه البيانات عبر الشبكة إلا إذا كانت الميزة تتطلب ذلك، وعندما تفعل ذلك، اذكر description وsummary ما الذي تم إرساله وإلى من. احتفظ بالبيانات الثابتة للمكون الإضافي في ملف ضمن المجلد الرئيسي للمستخدم المسمى باسم معرف المكون الإضافي، بحيث يسهل العثور عليه عند إلغاء التثبيت.

05الأدوات وبروتوكول الاتصال

تصريح

مجالوصف
nameاسم الأداة بأحرف صغيرة وشرطات سفلية، فريد عبر التطبيق بأكمله (يتم تسجيله في النموذج إلى جانب الأدوات المضمنة وأدوات المكونات الإضافية الأخرى).
descriptionوصف النموذج (باللغة الإنجليزية). اذكر ثلاثة أشياء: ما تفعله الأداة، وما يقوله المستخدم عندما ينبغي استدعاؤها، ومتى لا يجب استدعاؤها. هذا هو الحقل الأكثر أهمية لمعرفة ما إذا كان الذكاء الاصطناعي يستخدم المكون الإضافي الخاص بك.
summaryملخص مكون من سطر واحد يمكن قراءته بواسطة الإنسان ويظهر في صفحة الموافقة. اختياري ولكن يوصى به بشدة؛ وإلا فسيتم عرض وصف مقطوع بدلاً من ذلك.
parametersكائن مخطط JSON القياسي مع description في كل خاصية. يملأ النموذج الوسائط منه ويمررها المضيف دون التحقق الإضافي، لذا تحقق من الحقول المطلوبة في التعليمات البرمجية الخاصة بك.
renderAsخياري؛ حاليًا checklist فقط: يعرض المضيف المصفوفة todos من وسائط الاتصال كبطاقة قائمة مرجعية، انظر أدناه.
ملحوظة
يمكن للنموذج فقط استدعاء أسماء الأدوات المعلنة في tools[] هنا — sessionAction.tool، commands[].tool، والحقل tool داخل menus يتم تحديدها فقط لتكون سلاسل غير فارغة في وقت التثبيت؛ يقوم المضيف لا بالتحقق من إعلان الاسم في tools[]، ولا يزال يرسل مكالمة تحت هذا الاسم عند تشغيل الزر أو الاختصار أو عنصر القائمة. لذلك يمكن التعامل مع الإجراء الذي يتم تشغيله بواسطة واجهة المستخدم بشكل كامل في index.js دون الظهور على الإطلاق في tools[] — ولكن بعد ذلك لا يمكن للذكاء الاصطناعي رؤيته أو الاتصال به أبدًا. إذا كنت تريد أن يكون نفس الإجراء قابلاً للتنفيذ عن طريق النقر وعن طريق الذكاء الاصطناعي الذي يعمل بناءً على طلب دردشة، فقم بإعلان نفس الاسم في tools[] أيضًا، بحيث تشترك نقطتي الإدخال في معالج واحد؛ إذا كان من المفترض أن تظل واجهة المستخدم فقط، فاتركها غير معلنة - ليست هناك حاجة لإضافة إدخال فقط لتبدو كاملة.

بروتوكول الرسالة

يرسل المضيف call_tool؛ يجب أن يرد المكون الإضافي بـ tool_result أو tool_error يحمل نفس الرمز requestId. تنتهي مهلة المكالمة بدون الرد خلال 30 ثانية ويتلقى النموذج خطأ.

// host → plugin
{
  "type": "call_tool",
  "requestId": "0b2d…",          // unique per call, echo it back unchanged
  "toolName": "do_something",
  "params": { "name": "…" },     // arguments validated against tools[].parameters
  "context": {
    "cwd": "/Users/me/project",  // project folder of the calling session; a temp folder for chat sessions; empty string for document parsing
    "config": { "mode": "auto", "verbose": false }   // present only when configuration is declared; keys are configuration[].id
  }
}

content يقبل فقط text وimage الكتل (الصورة كـ base64 data زائد mimeType)؛ يتم إسقاط أنواع أخرى. details عبارة عن بيانات منظمة عشوائية لا يتم تغذيتها أبدًا للنموذج؛ إنه مخصص لعرض واجهة المستخدم المضيفة وطرق العرض الخاصة بك.

نتائج الملف: بطاقات الملفات

// When the result is a file: include the absolute path and file name. The session
// renders a clickable file card that previews in-app (docx/xlsx/pdf/markdown/code…).
process.send({
  type: 'tool_result',
  requestId,
  content: [{ type: 'text', text: `Generated [${fileName}](${filePath})` }],
  details: { filePath, fileName },
});

تقديم قائمة التحقق: renderAs checklist

// For tools with renderAs: "checklist", the host renders the todos array from the call arguments:
{
  "todos": [
    { "id": "1", "content": "Initialize repository", "status": "completed" },
    { "id": "2", "content": "Write unit tests", "status": "in_progress" },
    { "id": "3", "content": "Publish", "status": "pending" }
  ]
}

كتابة وصف جيد

قم بوصف المشغل في الأمر ("اتصل بهذا عندما يطلب المستخدم ...") واستثناءات الحالة ("لا تتصل بهذا لـ ..."). إذا كانت النتيجة ملفًا، فاطلب من النموذج الإشارة إلى رابط الملف الذي تم إرجاعه بدلاً من المطالبة بإنشائه. إذا تمت إعادة توجيه الوسائط إلى واجهة برمجة تطبيقات الجيل الخارجي، فاذكر اللغة التي يجب أن تكون بها. وتجنب السطور الفردية مثل "إدارة المهام"؛ لن يعرف النموذج متى يستخدم الأداة.

06طرق العرض الراسية (طرق العرض)

العرض الراسي هو صفحة ثابتة في الشريط الجانبي الأيمن للجلسة: يظهر رمز إضافي في شريط أدوات الجلسة ويظهر HTML الخاص بك على اليمين عند فتحه. تستمر حالة الصفحة (موضع التمرير، والمسودات) في تبديل الجلسات والطي/التوسيع، وهي نفس دلالات عرض الشريط الجانبي لـ VS Code.

مجالوصف
idفريدة من نوعها داخل البرنامج المساعد.
titleنص تلميح الأداة للرمز (يمكن قراءته بواسطة الإنسان).
iconاختر من القائمة المسموح بها للمضيف: git-branch، checklist. يحافظ على تناسق الرموز عبر التطبيق؛ لا يتم قبول الصور المخصصة.
entryملف HTML، نسبة إلى مجلد البرنامج المساعد.
widthعرض اللوحة الافتراضية الاختيارية بالبكسل، من 240 إلى 640، الافتراضي 360. يمكن للمستخدمين السحب لتغيير الحجم وتذكر الحجم.

وقت تشغيل الصفحة

تعمل الصفحة في وضع الحماية (sandbox + contextIsolation، بدون عقدة، لا يمكن الوصول إلى بيانات التطبيق المضيف) ولا يمكنها التحدث إلا إلى عملية المكونات الإضافية الخاصة بها من خلال الطرق القليلة الموجودة على window.pluginHost. أحضر أنماطك الخاصة؛ يوصى باتباع نظام الإضاءة/الظلام الخاص بالتطبيق كما هو موضح في المثال أدناه.

interface PluginHost {
  // Call a tool declared in this plugin's manifest.tools; same call_tool channel the AI uses
  invoke(toolName: string, params: unknown): Promise<
    { content: unknown[]; details?: unknown } | { error: string }
  >;
  // Subscribe to ui_push messages from the plugin process; returns an unsubscribe function
  onPush(callback: (channel: string, payload: unknown) => void): () => void;
  // Current light/dark scheme and subsequent changes
  getColorScheme(): Promise<'light' | 'dark'>;
  onColorSchemeChange(callback: (scheme: 'light' | 'dark') => void): () => void;
}
declare const pluginHost: PluginHost; // exposed as window.pluginHost

النمط الموصى به: عند التحميل الأول، اتصل بإحدى أدوات الاستعلام الخاصة بك باستخدام invoke() واطلب منها إرجاع البيانات المنظمة في details؛ بعد ذلك، ادفع كل تغيير من عملية البرنامج الإضافي باستخدام ui_push بدلاً من الاقتراع. عندما يقوم الذكاء الاصطناعي بتغيير البيانات في المحادثة، يتم تحديث اللوحة على الفور.

07اللوحة العائمة (واجهة المستخدم)

ui: { entry, title } يعلن عن نافذة عائمة مستقلة (900×700) يفتحها المستخدمون من القائمة "⋯" في قائمة المكونات الإضافية؛ تم تدميره على مقربة. تتطابق بيئة الصفحة وواجهة برمجة التطبيقات window.pluginHost مع طرق العرض المُرساة، ويتم تسليم ui_push إلى كل من اللوحة العائمة وطرق العرض المُرساة. مناسبة للألواح الكبيرة المفتوحة من حين لآخر؛ استخدم views للمحتوى الذي يجب أن يبقى بجوار الجلسة.

08رمز شريط أدوات الجلسة (sessionAction)

رمز ثابت واحد على الأكثر لكل مكون إضافي. يؤدي النقر عليها إلى استدعاء tool باستخدام وسائط فارغة، لذا يجب على هذه الأداة أن تفعل شيئًا ذا معنى بدون معلمات.

مجالوصف
toolأداة للاتصال عند النقر.
iconاسم رمز القائمة المسموح بها.
tooltipتحوم النص.
visibleToolخياري. عند التعيين، يتم استدعاؤه باستخدام وسيطات فارغة قبل العرض ويقرر القيمة المنطقية details.visible في النتيجة ما إذا كان الرمز سيظهر أم لا. مفيد لعمليات التحقق في وقت التشغيل مثل "هل المجلد الحالي هو مستودع git".
// The host calls visibleTool with empty params and shows the icon based on details.visible
process.send({
  type: 'tool_result',
  requestId,
  content: [{ type: 'text', text: isGitRepo ? 'git repo' : 'not a git repo' }],
  details: { visible: isGitRepo },
});

09الإعدادات (التكوين)

تظهر الإدخالات المعلنة ضمن تكوين البرنامج المساعد في صفحة الإعدادات. يقوم المضيف بتخزين القيم التي تم تغييرها من قبل المستخدم ويمررها كـ context.config في كل call_tool (مفتاح بواسطة id، والعودة إلى defaultValue)، سواء كانت المكالمة تأتي من الذكاء الاصطناعي، أو رمز شريط الأدوات أو اللوحة الخاصة بك. لا تحتاج أبدا إلى السؤال عنهم.

typeقدمت كمانوع القيمة الافتراضية
selectقائمة الاختيار الواحد؛ الخيارات تأتي من optionsToolstring
booleanتبديل التبديلboolean
stringإدخال النص، ملتزم بالطمسstring
numberإدخال الرقمnumber
// For type: "select" settings, the host calls optionsTool with empty params to fetch options
process.send({
  type: 'tool_result',
  requestId,
  content: [{ type: 'text', text: '2 options' }],
  details: {
    options: [
      { value: 'fast', label: 'Fast' },
      { value: 'accurate', label: 'Accurate' },
    ],
  },
});
// The host automatically prepends an "Auto" option whose value equals this
// configuration entry's defaultValue; the plugin must not return it again.

10لوحة الأوامر / الاختصارات / قائمة السياق

الثلاثة جميعها عبارة عن نقاط دخول مختلفة لـ "استدعاء أداة ذات وسيطات فارغة"؛ يمكن للمكون الإضافي أن يعلن عن عدة.

مجالشكلوصف
commands{ tool, icon, title }[]يظهر في لوحة الأوامر Ctrl/Cmd+K ويتم تشغيله بعد أن يبحث المستخدم عنه.
keybindings{ command, key }[]command يجب أن يساوي tool للإدخال في commands[]. key يستخدم الترميز mod+shift+g، حيث mod هو Cmd على macOS وCtrl في مكان آخر. لا يتم التحقق من التعارضات مع الاختصارات الأخرى بشكل ثابت، لذا اختر مجموعات غير شائعة.
menus{ "session/context": { tool, icon, title }[] }تمت إضافتها إلى القائمة في صف الجلسة. هذا الموقع فقط متاح في الوقت الراهن.

11محللو المستندات (موزعو المستندات)

عندما يقوم المستخدم بإسقاط ملف في مربع الإدخال، يبحث المضيف عن المحللين المعلنين بواسطة المكونات الإضافية الممكّنة حسب نوع MIME ويمرر محتوى الملف كـ base64 إلى المطابقة toolName. هذه ليست أداة يقرر الذكاء الاصطناعي الاتصال بها، لذا افعل not أيضًا أدرج أداة المحلل اللغوي ضمن tools، وإلا سيتم كشفها كأداة قابلة للاستدعاء بواسطة الذكاء الاصطناعي.

// The toolName declared in documentParsers is called when the user drops a file into the input:
// params = { base64: "<file content as base64>" }
// Return: details must be { success: true, text } or { success: false, reason }
process.on('message', (msg) => {
  if (msg.type !== 'call_tool' || msg.toolName !== 'parse_markdown') return;
  const text = Buffer.from(msg.params.base64, 'base64').toString('utf8');
  process.send({
    type: 'tool_result',
    requestId: msg.requestId,
    content: [{ type: 'text', text: 'parsed' }],
    details: { success: true, text },
  });
});

12عكس RPC (طلب_المضيف)

لا تحتوي عملية البرنامج المساعد على Electron API. عندما يحتاج إلى قدرة نظام حقيقية فإنه يرسل host_request إلى المضيف، الذي يرد بـ host_response أو host_error. هذه القناة مستقلة تماما عن call_tool؛ يمكنك استخدامه أثناء التعامل مع استدعاء أداة أو من جهاز توقيت.

capabilityparamsresultشرط مسبق
show_notification{ title, body?, viewId? }{ shown: true } / { shown: false, reason: "disabled" | "unsupported" }يتطلب إذن notifications. تم تعطيل الإرجاع بدلاً من ظهور خطأ عندما قام المستخدم بإيقاف تشغيل إشعارات سطح المكتب في الإعدادات. عندما يشير viewId إلى إحدى طرق العرض المثبتة، يؤدي النقر فوق الإشعار إلى جلب التطبيق إلى المقدمة وتوسيع هذا العرض.
render_pdf{ outputPath, title, content }{}المحتوى هو تخفيض السعر؛ يعرض المضيف ملف PDF إلى مسار الإخراج باستخدام العارض المدمج الخاص به.
const crypto = require('crypto');
const pending = new Map();

function requestHost(capability, params) {
  const requestId = crypto.randomUUID();
  return new Promise((resolve, reject) => {
    const timer = setTimeout(() => {
      pending.delete(requestId);
      reject(new Error(`host capability "${capability}" timed out`));
    }, 30_000);
    pending.set(requestId, { resolve, reject, timer });
    process.send({ type: 'host_request', requestId, capability, params });
  });
}

process.on('message', (msg) => {
  if (msg.type === 'host_response' || msg.type === 'host_error') {
    const p = pending.get(msg.requestId);
    if (!p) return;
    pending.delete(msg.requestId);
    clearTimeout(p.timer);
    if (msg.type === 'host_error') p.reject(new Error(msg.message));
    else p.resolve(msg.result);
  }
});

// usage
await requestHost('show_notification', {
  title: '3 todos for today',
  body: '• Write weekly report\n• Reply to emails',
  viewId: 'board',      // optional: expand this docked view when the notification is clicked
});
// => { shown: true } or { shown: false, reason: 'disabled' | 'unsupported' }

await requestHost('render_pdf', {
  outputPath: '/abs/path/report.pdf',
  title: 'Report',
  content: '# Title\n\nBody (Markdown)',
});

13دورة الحياة

منصةسلوك
يبدأكسول بشكل افتراضي: لم يبدأ مع التطبيق، تم تشعبه عند الاتصال الأول بإحدى أدواتك (الذكاء الاصطناعي، رمز شريط الأدوات، اللوحة، الأمر، تحليل المستند). تبدأ المكونات الإضافية التي تعلن activationEvents: ["onStartupFinished"] مباشرة بعد انتهاء تشغيل التطبيق؛ استخدم هذا فقط للمكونات الإضافية التي تحتاج إلى مؤقتات في الخلفية (التذكيرات والاستقصاء)، وليس للمكونات الإضافية للأدوات العادية.
مقيمبمجرد البدء، تظل العملية حية ويتم إعادة استخدامها عبر استدعاءات الأداة. يمكنك تخزين الحالة مؤقتًا في الذاكرة، ولكن افترض أنه يمكن إعادة تشغيلها في أي وقت.
يتحطمإذا خرجت العملية بشكل غير متوقع، فسيقوم المضيف بإعادة تشغيلها: على الفور، ثم بعد 5 و15 ثانية. بعد 3 حالات فشل متتالية، يتم وضع علامة "تعطل" عليه ولم يعد يحاول مرة أخرى؛ يرى المستخدمون الحالة على صفحة البرنامج المساعد. المكالمات على متن الطائرة جميع أخطاء العودة.
تعطيل / إلغاء التثبيت / إعادة التثبيتيتم إنهاء العملية وتدمير طرق العرض المثبتة واللوحات العائمة؛ تؤدي عملية إعادة التثبيت إلى استبدال المجلد بأكمله.
سجلاتتتم كتابة stdout/stderr في ملف سجل التطبيق مسبوقًا بمعرف البرنامج المساعد. عادي console.log يكفي لتصحيح الأخطاء؛ راجع "تصحيح الأخطاء والأسئلة الشائعة".
بيئى
تبدأ العملية الفرعية بـ ELECTRON_RUN_AS_NODE=1، cwd هو مجلد تثبيت المكون الإضافي، ويتطابق إصدار Node مع Electron المرفق مع التطبيق. لا تعتمد على أي حزمة مثبتة عالميًا ولا تفترض وجود npx.

14التعبئة والتغليف والنشر

التعبئة والتغليف

قم بضغط مجلد البرنامج الإضافي باستخدام manifest.json في جذر الأرشيف. إذا كانت لديك تبعيات تابعة لجهات خارجية، فقم بتجميعها في ملف واحد باستخدام esbuild/webpack أولاً بدلاً من شحن node_modules بالكامل.

my-plugin.zip
├── manifest.json     # must be at the archive root
├── icon.png          # optional, referenced by manifest.icon
├── index.js
├── view.html
└── node_modules/…    # include dependencies if any (bundling into a single file is recommended)

النشر إلى السوق

AnBoWork → الأدوات → المكونات الإضافية → علامة التبويب "السوق" → "نشر المكون الإضافي" في الزاوية العلوية اليمنى، ثم قم بتحميل الملف المضغوط. تخضع التقديمات للمراجعة، والتي تتحقق من تطابق إعلان البيان مع الكود (خاصة الأذونات). بمجرد الموافقة عليه، يمكن للمستخدمين الآخرين العثور عليه وتثبيته في السوق، ويمكن للذكاء الاصطناعي تثبيت المكونات الإضافية التي تم التحقق منها للمستخدمين تلقائيًا عندما يرى الحاجة إليها.

التحديثات

عثرة version ونشر مرة أخرى. يقارن التطبيق الإصدار المثبت مع إصدار السوق ويطالبك بالتحديث؛ تؤدي إعادة التثبيت إلى الاحتفاظ بحالة المستخدم وقيم الإعدادات الممكّنة.

15مثال كامل: تودو كوادرانت

مكون إضافي فعال (مقتطع): يمكن للذكاء الاصطناعي إضافة المهام وإزالتها، ويعرض الشريط الجانبي الأيمن لوحة يتم تحديثها في الوقت الفعلي، ويمكنه إرسال تذكيرات بإشعارات النظام. يغطي تسلسل هذه الثلاثة بروتوكول الأداة ودفعات العرض المثبتة وRPC العكسي.

{
  "id": "local.todo-quadrant",
  "name": "Todo Quadrant",
  "version": "1.2.0",
  "description": "Daily todo list organized by the Eisenhower matrix. Install this whenever the user wants to track tasks or asks to be reminded about something…",
  "main": "index.js",
  "permissions": ["filesystem", "notifications"],
  "activationEvents": ["onStartupFinished"],
  "tools": [{
    "name": "manage_todo_quadrant",
    "summary": "Add, list, complete, delete and update todos in an urgent/important matrix",
    "description": "Manage the user's daily todo list… Actions: add / list / complete / delete / update / set_reminder / remind_now. add/update also accept remind_at to schedule a one-time reminder for that specific todo. Call this whenever the user talks about their todos…",
    "parameters": {
      "type": "object",
      "properties": {
        "action": { "type": "string", "enum": ["add", "list", "complete", "delete", "update", "set_reminder", "remind_now"] },
        "id": { "type": "string" },
        "content": { "type": "string" },
        "quadrant": { "type": "string", "enum": ["urgent_important", "important_not_urgent", "urgent_not_important", "not_urgent_not_important"] },
        "due_date": { "type": "string", "description": "YYYY-MM-DD" },
        "remind_at": { "type": "string", "description": "YYYY-MM-DD HH:MM — a one-time reminder for this todo, independent of the daily digest" }
      },
      "required": ["action"]
    }
  }],
  "views": [{ "id": "quadrant", "title": "Todo Quadrant", "icon": "checklist", "entry": "view.html", "width": 380 }]
}

16تصحيح الأخطاء والأسئلة الشائعة

أعراضالسبب والإصلاح
فشل التحقق من صحة البيان عند التثبيتتحقق من كل حقل مقابل جدول "حقول البيان" كما تشير الرسالة: تنسيق المعرف، يجب ألا يحتوي الإدخال الرئيسي/الإدخال على ..، يجب إدراج الرمز في القائمة المسموح بها، ويجب أن يشير أمر ربط المفاتيح إلى أداة موجودة في الأوامر، بعرض يتراوح بين 240 و640.
الذكاء الاصطناعي لا يستدعي أداتي أبدًادائمًا ما تكون مشكلة description: المشغل غير واضح أو أنه غير مكتوب باللغة الإنجليزية. راجع "كتابة وصف جيد". تأكد أيضًا من عدم تعارض اسم الأداة مع أداة أخرى.
مهلة المكالمة (30 ثانية)لم يرد نص الإدخال بـ tool_result. عادةً لم يتم تكرار requestId مرة أخرى، أو أن الرسالة type بها خطأ إملائي، أو تم طرح البرنامج النصي عند بدء التشغيل والخروج. ابحث عن الخطوط التي تسبقها [plugin:your-id] في سجل التطبيق.
تظهر حالة البرنامج المساعد "تعطلت"3 بدايات فاشلة متتالية عادة require من الحزمة المفقودة؛ يؤدي تشغيل node index.js في مجلد البرنامج المساعد إلى إعادة إنتاجه. بعد الإصلاح، قم بإيقاف تشغيل المكون الإضافي وتشغيله مرة أخرى في صفحة المكون الإضافي.
تفتح اللوحة فارغةمسار entry خاطئ، أو خطأ JS في الصفحة. يتم تشغيل الصفحة في وضع الحماية بدون عقدة require; متوفر window.pluginHost فقط.
لا يظهر الإخطارتحقق بالترتيب: يعلن البيان notifications؛ والنتيجة ليست shown:false (قام المستخدم بإيقاف تشغيل إشعارات سطح المكتب)؛ يسمح نظام التشغيل بالإشعارات من AnBoWork.
قيم الإعدادات غير قابلة للقراءةالقيم موجودة في message.context.config[id]، وليس في params.

موقع ملف السجل

نظام التشغيلطريق
macOS~/Library/Logs/AnBoWork/main.log
Windows%USERPROFILE%\AppData\Roaming\AnBoWork\logs\main.log
راجع مستندات تكامل API