// راهنمای توسعه دهنده

اسناد توسعه دهنده پلاگین

برای برنامه دسکتاپ AnBoWork پلاگین بسازید: ابزارهای جدید برای هوش مصنوعی اضافه کنید، پانل خود را در کنار یک جلسه قرار دهید، اعلان‌های سیستم را ارسال کنید، قالب‌های فایل جدید را تجزیه کنید. یک manifest.json به اضافه یک اسکریپت ورودی برای شروع کافی است.

01نمای کلی

یک پلاگین AnBoWork یک برنامه Node.js ساده است. پس از نصب، برنامه آن را به عنوان یک فرآیند فرزند مستقل (نود خالص، بدون Electron API) تقسیم می‌کند و از طریق پیام‌های بین فرآیندی با آن صحبت می‌کند. هیچ بسته SDK مورد نیاز نیست. تنها چیزی که نیاز دارید process.on('message') و process.send() است.

هر کاری که یک افزونه می‌تواند انجام دهد به صورت ایستا در manifest.json اعلام می‌شود: صفحه رضایت پیش‌نصب و بررسی بازار می‌تواند بفهمد که چه ابزارهایی را اضافه می‌کند و به کدام مجوزها نیاز دارد بدون اینکه هیچ کد افزونه اجرا شود. همه UI (آیکون های نوار ابزار، تنظیمات، پالت فرمان، منوهای زمینه) توسط میزبان از اعلان ارائه می شود. کد پلاگین هرگز در پنجره اصلی اجرا نمی شود. فقط نماهای متصل و پانل های شناور 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. manifest.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.

قراردادهای زبان برای متن

Text in the manifest has two audiences. For the model: name, description, tools[].description, tools[].parameters.*.description. Write these in English; models understand English tool descriptions and fill parameters more reliably. For people: tools[].summary (one-line summary on the consent page), ui.title, views[].title, sessionAction.tooltip, configuration[].label, commands[].title and title inside menus. Write these in your target users' language.

{
  "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انجام هرگونه درخواست شبکه (APIهای شخص ثالث، دانلودها)رضایت آگاهانه، نشان داده شده به کاربر.
notificationsنمایش اعلان‌های سیستم از طریق RPC معکوس show_notificationاجرا شده: فراخوانی آن بدون اعلان، host_error را برمی‌گرداند و هیچ اعلانی نشان داده نمی‌شود.
توجه
فرآیند فرزند افزونه یک محیط Node.js کامل است. filesystem و network در حال حاضر اعلان‌های سطح رضایت هستند، نه جعبه ایمنی زمان اجرا: میزبان fs یا fetch را رهگیری نمی‌کند. دقیقاً به همین دلیل است که اعلامیه ها باید صادقانه باشند. افزونه‌هایی که کمتر اعلام می‌شوند در بررسی بازار رد می‌شوند و پس از کشف اعتماد کاربران را از دست می‌دهند. بیش از حد اعلام نکنید (مجوزهای استفاده نشده باعث تردید کاربران می شود).

حریم خصوصی و داده ها

context.cwd پوشه پروژه کاربر است و ممکن است حاوی کد منبع و پیکربندی حساس باشد. آرگومان های ابزار ممکن است حاوی مکالمه کاربر باشد. این داده ها را از طریق شبکه ارسال نکنید، مگر اینکه ویژگی آن را ایجاب کند، و زمانی که انجام دادید، در description و summary بنویسید چه چیزی و به چه کسی ارسال شده است. داده‌های دائمی خود افزونه را در فایلی در زیر پوشه اصلی کاربر با نام شناسه افزونه نگه دارید، بنابراین هنگام حذف نصب آسان است.

05ابزارها و پروتکل تماس

اعلامیه

میدانتوضیحات
nameنام ابزار با حروف کوچک و زیرخط، منحصر به فرد در کل برنامه (در مدل در کنار ابزارهای داخلی و ابزارهای دیگر افزونه ها ثبت شده است).
descriptionتوضیحات برای مدل (انگلیسی). سه چیز را بیان کنید: ابزار چه کاری انجام می دهد، کاربر چه زمانی می گوید که باید آن را فراخوانی کرد و چه زمانی نباید آن را فراخوانی کرد. این تنها مهمترین زمینه برای اینکه آیا هوش مصنوعی از افزونه شما استفاده می کند یا خیر است.
summaryخلاصه یک خطی قابل خواندن توسط انسان در صفحه رضایت نشان داده شده است. اختیاری اما به شدت توصیه می شود. در غیر این صورت یک توضیح کوتاه به جای آن نشان داده می شود.
parametersشی استاندارد JSON Schema با description در هر ویژگی. مدل آرگومان ها را از آن پر می کند و میزبان آنها را بدون اعتبار سنجی اضافی عبور می دهد، بنابراین فیلدهای مورد نیاز در کد خود را بررسی کنید.
renderAsاختیاری؛ در حال حاضر فقط checklist: میزبان آرایه todos را از آرگومان های فراخوانی به عنوان یک کارت چک لیست ارائه می کند، به زیر مراجعه کنید.
توجه داشته باشید
مدل فقط می‌تواند نام ابزارهای اعلام شده در tools[] را در اینجا فراخوانی کند — sessionAction.tool، commands[].tool، و فیلد tool داخل menus فقط در زمان نصب علامت زده می‌شود که رشته‌های خالی نباشد. میزبان نه تأیید می‌کند که نام در tools[] اعلام شده است، و همچنان هنگامی که دکمه، میانبر یا آیتم منو فعال می‌شود، تماسی را تحت آن نام ارسال می‌کند. بنابراین، یک اقدام صرفاً توسط UI را می‌توان به طور کامل در index.js خودتان بدون اینکه در tools[] ظاهر شود، مدیریت کرد - اما پس از آن هوش مصنوعی هرگز نمی‌تواند آن را ببیند یا فراخوانی کند. اگر می‌خواهید هم با کلیک کردن و هم توسط هوش مصنوعی که روی یک درخواست چت عمل می‌کند، یک عمل فعال شود، همان نام را در tools[] نیز اعلام کنید، بنابراین هر دو نقطه ورودی یک کنترل‌کننده را به اشتراک می‌گذارند. اگر قرار است فقط UI باقی بماند، آن را اعلام نشده رها کنید - نیازی به اضافه کردن یک ورودی نیست تا کامل به نظر برسد.

پروتکل پیام

میزبان 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 چک لیست

// 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" }
  ]
}

نوشتن توضیحات خوب

ماشه را در دستور ضروری توصیف کنید ("زمانی که کاربر درخواست می کند این را صدا کنید") و موارد استثنا را بیان کنید ("این را برای ... تماس نگیرید"). اگر نتیجه یک فایل است، از مدل بخواهید به جای اینکه ادعا کند ایجاد شده است، به پیوند فایل برگشتی اشاره کند. اگر آرگومان‌ها به یک API نسل خارجی ارسال می‌شوند، بگویید به کدام زبان باید باشند. مدل نمی داند چه زمانی از ابزار استفاده کند.

06نماهای متصل (نماها)

نمای داک شده یک صفحه ثابت در نوار کناری سمت راست جلسه است: یک نماد اضافی در نوار ابزار جلسه ظاهر می شود و HTML شما در سمت راست هنگام باز شدن نشان داده می شود. حالت صفحه (موقعیت اسکرول، پیش‌نویس‌ها) از جلسات تعویض و جمع‌کردن/بسط می‌یابد، معنایی مشابه نمای نوار کناری VS Code.

میدانتوضیحات
idمنحصر به فرد در داخل افزونه.
titleمتن راهنمای ابزار برای نماد (قابل خواندن توسط انسان).
iconاز لیست مجاز میزبان انتخاب کنید: git-branch، checklist. نمادها را در سراسر برنامه ثابت نگه می دارد. تصاویر سفارشی پذیرفته نمی شوند.
entryفایل HTML، نسبت به پوشه پلاگین.
widthپهنای پنل پیش‌فرض اختیاری بر حسب پیکسل، 240 تا 640، 360 پیش‌فرض. کاربران می‌توانند اندازه را بکشند و اندازه را به خاطر بسپارند.

زمان اجرای صفحه

صفحه در جعبه ایمنی اجرا می‌شود (sandbox + contextIsolation، بدون Node، بدون دسترسی به داده‌های برنامه میزبان) و فقط می‌تواند از طریق چند روش در 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)

ui: { entry, title } یک پنجره شناور مستقل (900×700) را اعلام می کند که کاربران از منوی "⋯" در لیست افزونه ها باز می کنند. در نزدیکی نابود می شود. محیط صفحه و window.pluginHost API با نماهای docked یکسان هستند و ui_push هم به پانل شناور و هم به نماهای docked تحویل داده می‌شود. مناسب برای پانل های بزرگ که گاهی اوقات باز می شوند. برای محتوایی که باید در کنار جلسه بماند از 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 برمی‌گرداند) ارسال می‌کند، چه تماس از AI، نماد نوار ابزار یا پانل شما باشد. شما هرگز نیازی به درخواست آنها ندارید.

typeارائه شده به عنواننوع مقدار پیش فرض
selectلیست تک گزینه ای؛ گزینه ها از optionsTool می آیندstring
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تجزیه کننده های اسناد (documentParsers)

وقتی کاربر فایلی را در کادر ورودی می‌اندازد، میزبان تجزیه‌کننده‌های اعلام‌شده توسط پلاگین‌های فعال شده با نوع 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 },
  });
});

12RPC معکوس (host_request)

فرآیند افزونه فاقد 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 }{}محتوا Markdown است. میزبان یک PDF را با رندر داخلی خود به outputPath ارائه می کند.
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 برای اشکال زدایی کافی است. به «اشکال‌زدایی و سؤالات متداول» مراجعه کنید.
ENV
فرآیند فرزند با ELECTRON_RUN_AS_NODE=1 شروع می‌شود، cwd پوشه نصب افزونه است، و نسخه Node با Electron همراه با برنامه مطابقت دارد. به هیچ بسته نصب شده جهانی وابسته نباشید و فرض نکنید npx وجود دارد.

14بسته بندی و انتشارات

بسته بندی

پوشه افزونه را با manifest.json در ریشه آرشیو زیپ کنید. اگر وابستگی های شخص ثالث دارید، به جای ارسال کل node_modules، ابتدا آنها را در یک فایل با esbuild/webpack قرار دهید.

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 ← ابزار ← افزونه ها ← برگه "Marketplace" → "Publish plugin" در گوشه سمت راست بالا، سپس فایل فشرده را آپلود کنید. ارسال‌ها وارد بازبینی می‌شوند، که بررسی می‌کند اعلامیه مانیفست با کد مطابقت داشته باشد (مخصوصاً مجوزها). پس از تأیید، سایر کاربران می توانند آن را پیدا کرده و در بازار نصب کنند، و هوش مصنوعی می تواند در صورت نیاز، افزونه های تأیید شده را به طور خودکار برای کاربران نصب کند.

به روز رسانی ها

ضربه بزنید version و دوباره منتشر کنید. برنامه نسخه نصب شده را با نسخه بازار مقایسه می کند و به روز رسانی را می خواهد. نصب مجدد وضعیت فعال و مقادیر تنظیمات کاربر را حفظ می کند.

15مثال کامل: Todo Quadrant

یک افزونه واقعی و کارآمد (بریده‌شده): هوش مصنوعی می‌تواند کارها را اضافه و حذف کند، نوار کناری سمت راست تابلویی را نشان می‌دهد که در زمان واقعی تازه‌سازی می‌شود، و می‌تواند یادآوری‌های اعلان سیستم را ارسال کند. زنجیر کردن این سه، پروتکل ابزار، فشارهای docked-view و 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اشکال زدایی و سوالات متداول

علامتعلت و رفع
تأیید اعتبار مانیفست هنگام نصب ناموفق استهر فیلد را با جدول "Manifest Fields" بررسی کنید، همانطور که پیام نشان می دهد: فرمت شناسه، اصلی/ورودی نباید حاوی .. باشد، نماد باید در لیست مجاز باشد، دستور keybindings باید به ابزار موجود در دستورات اشاره کند، عرض بین 240 و 640.
هوش مصنوعی هرگز ابزار من را صدا نمی کندتقریباً همیشه یک مشکل description: ماشه نامشخص است یا به زبان انگلیسی نوشته نشده است. به "نوشتن توضیحات خوب" مراجعه کنید. همچنین بررسی کنید که نام ابزار با ابزار دیگری برخورد نکند.
زمان پایان تماس (30 ثانیه)اسکریپت ورودی با tool_result پاسخ نداد. معمولاً requestId بازتاب داده نمی‌شود، پیام type اشتباه نوشته می‌شود یا اسکریپت هنگام راه‌اندازی پرتاب می‌شود و خارج می‌شود. به دنبال خطوط با پیشوند [plugin:your-id] در گزارش برنامه بگردید.
وضعیت پلاگین "خراب شده" را نشان می دهد3 شروع ناموفق متوالی. معمولاً یک require از یک بسته گم شده؛ اجرای node index.js در پوشه پلاگین آن را بازتولید می کند. پس از رفع مشکل، افزونه را خاموش و دوباره در صفحه افزونه روشن کنید.
پنل خالی باز می شودمسیر entry اشتباه، یا خطای JS در صفحه. صفحه در sandbox بدون require Node اجرا می شود. فقط 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 مراجعه کنید