// מדריך למפתחים

תוסף מפתח מסמכים

בנו תוספים עבור אפליקציית שולחן העבודה AnBoWork: הוסף כלים חדשים עבור AI, עגן פאנל משלך ליד הפעלה, שלח הודעות מערכת, נתח פורמטים חדשים של קבצים. מספיק manifest.json בתוספת סקריפט כניסה אחד כדי להתחיל.

01סקירה כללית

תוסף AnBoWork הוא תוכנית Node.js רגילה. לאחר ההתקנה, האפליקציה מעבירה אותה כתהליך ילד עצמאי (צומת טהור, ללא Electron API) ומדברת איתו על הודעות בין תהליכים. אין צורך בחבילת SDK; כל מה שאתה צריך זה process.on('message') וprocess.send().

כל מה שתוסף יכול לעשות מוצהר באופן סטטי ב-manifest.json: דף ההסכמה להתקנה מראש וסקירת השוק יכולים לדעת אילו כלים הוא מוסיף ואיזה הרשאות הוא צריך מבלי להפעיל שום קוד פלאגין. כל ממשק המשתמש (סמלים של סרגל הכלים, הגדרות, לוח הפקודות, תפריטי הקשר) מוצג על ידי המארח מההצהרה; קוד הפלאגין לעולם אינו פועל בתוך החלון הראשי. רק תצוגות מעוינות ופאנלים צפים הם HTML משלך, והם פועלים בדפים מבודדים בארגז חול.

יכולות במבט חטוף

שדה מניפסטיְכוֹלֶתאיפה המשתמשים רואים את זה
toolsהוסף כלים הניתנים להתקשרות עבור ה-AIה-AI קורא להם באופן אוטומטי בשיחה; שיחות כלי מוצגות בהפעלה
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 → סרגל עליון "כלים" → "תוספים" → "התקן מקומי" בפינה השמאלית העליונה, ולאחר מכן בחר את תיקיית הפלאגין (או zip שלה). דף הסכמה מפרט את ההרשאות המוצהרות וכל כלי לפני ההתקנה; אשר כדי להפעיל.

4. נסה את זה

בכל הפעלה, אמור ל-AI "בקש מהפלאגין לומר שלום לאליס". בהתבסס על תיאור הכלי ה-AI מחליט לקרוא ל-say_hello, והקריאה והתוצאה שלה מופיעות בסשן.

עֵצָה
ה-AI בתוך AnBoWork יכול גם ליצור תוספים עבורך (תגיד "כתוב לי תוסף שעושה X" והוא קורא create_local_plugin). תוספים שנוצרו מושבתים כברירת מחדל עד שתבדוק את הקוד בדף הפלאגין ותפעיל אותם באופן ידני. מדריך זה חל באופן שווה על קריאה ושינוי תוספים שנוצרו בינה מלאכותית.

03שדות מניפסט

שָׂדֶהסוּגדָרוּשׁתֵאוּר
idstringכֵּןסגנון תחום הפוך, למשל. com.example.my-plugin. אותיות, ספרות, נקודות ומקפים בלבד. בלתי ניתן לשינוי ברגע שנוצר; התקנה חוזרת של אותו מזהה מטופלת כהתקנה מחדש.
namestringכֵּןשם הפלאגין. יחד עם description הוא מוזן למודל כהקשר, לכן מומלץ באנגלית.
versionstringכֵּןגרסה סמנטית; השוק משתמש בו כדי לזהות עדכונים.
descriptionstringכֵּןמשפט אחד שמתאר מה התוסף עושה (אנגלית).
authorstringלֹאמְחַבֵּר.
readmestringלֹאתיאור ארוך המוצג בדף הפרטים של השוק, תומך ב-Markdown. תמונות בתוכו חייבות להיות https כתובות URL - נתיבים יחסיים לקבצים המצורפים ב-zip אינם נתמכים.
iconstringלֹאסמל המוצג ברשימת השוק ובדף הפרטים - נתיב יחסי לקובץ ארוז ב-zip (למשל 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 חייב לשקף בכנות את מה שהקוד עושה בפועל. דף ההסכמה מראש להתקנה מפרט כל אחד מהם כך שמשתמשים יכולים להחליט אם להתקין; סקירת marketplace גם בודקת את ההצהרה מול הקוד.

רְשׁוּתמתי יש להצהיר על כךאיך המארח מתייחס לזה
filesystemקריאה או כתיבה של קבצי משתמש (קריאת קוד פרויקט, הפקת מסמכים, אחסון נתונים בתיקיית הבית)הסכמה מדעת, מוצגת למשתמש.
networkביצוע כל בקשת רשת (ממשקי API של צד שלישי, הורדות)הסכמה מדעת, מוצגת למשתמש.
notificationsהצגת התראות מערכת באמצעות ה-RPC ההפוכה show_notification נאכף: קריאה אליו ללא ההצהרה מחזירה host_error ולא מוצגת התראה.
פֶּתֶק
תהליך הילד של הפלאגין הוא סביבת Node.js מלאה. filesystem ו-network הן כרגע הצהרות ברמת הסכמה, לא ארגז חול של זמן ריצה: המארח לא מיירט את fs או fetch. בדיוק בגלל זה הצהרות חייבות להיות כנות. תוספים שמוצהרים בחסר נדחים בסקירת השוק ומאבדים את אמון המשתמש כאשר הם מתגלים. גם אל תצהיר יתר על המידה (הרשאות שאינן בשימוש גורמות למשתמשים להסס).

פרטיות ונתונים

context.cwd היא תיקיית הפרויקט של המשתמש ועשויה להכיל קוד מקור ותצורה רגישה; ארגומנטים של כלי עשויים להכיל את השיחה של המשתמש. אל תשלח נתונים אלה דרך הרשת אלא אם התכונה דורשת זאת, וכאשר תעשה זאת, ציין ב-description ו-summary מה נשלח ולמי. שמור את הנתונים הקבועים של התוסף עצמו בקובץ תחת תיקיית הבית של המשתמש הקרויה על שם מזהה התוסף, כך שקל למצוא אותו בעת הסרת ההתקנה.

05כלים ופרוטוקול שיחות

הַצהָרָה

שָׂדֶהתֵאוּר
nameשם הכלי באותיות קטנות וקווים תחתונים, ייחודי בכל האפליקציה (הוא רשום בדגם לצד כלים מובנים וכלי תוספים אחרים).
descriptionתיאור הדגם (אנגלית). ציינו שלושה דברים: מה הכלי עושה, מה אומר המשתמש מתי צריך לקרוא לו ומתי אסור לקרוא לו. זהו השדה החשוב ביותר עבור האם ה-AI משתמש בתוסף שלך.
summaryסיכום קריא אנושי בשורה אחת המוצג בדף ההסכמה. אופציונלי אך מומלץ בחום; אחרת מוצג במקום תיאור קטום.
parametersאובייקט JSON Schema סטנדרטי עם description בכל מאפיין. המודל ממלא ארגומנטים ממנו והמארח מעביר אותם ללא אימות נוסף, אז בדוק שדות חובה בקוד שלך.
renderAsאופציונלי; כרגע רק checklist: המארח מעבד את מערך todos מארגומנטי השיחה ככרטיס רשימת בדיקה, ראה להלן.
פֶּתֶק
המודל יכול לקרוא רק לשמות הכלים המוצהרים ב-tools[] כאן - sessionAction.tool, commands[].tool והשדה tool בתוך menus מסומנים רק כמחרוזות לא ריקות בזמן ההתקנה; המארח לא מאמת שהשם מוצהר בtools[], ועדיין שולח שיחה תחת השם הזה כשהלחצן, קיצור הדרך או פריט התפריט מופעלים. אז ניתן לטפל בפעולה טהורה המופעלת על ידי ממשק משתמש ב-index.js שלך מבלי להופיע ב-tools[] - אבל אז ה-AI לעולם לא יוכל לראות או לקרוא לזה. אם אתה רוצה שאותה פעולה תהיה ניתנת להפעלה הן על ידי לחיצה והן על ידי הבינה המלאכותית הפועלת על בקשת צ'אט, הכריז גם על אותו שם ב-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

// 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 של דור חיצוני, אמור באיזו שפה הם צריכים להיות. הימנע מ-one-liners כמו "manage todos"; המודל לא יידע מתי להשתמש בכלי.

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 במקום סקר. כאשר ה-AI משנה נתונים בשיחה, הפאנל מתרענן מיד.

07פאנל צף (UI)

ui: { entry, title } מכריז על חלון צף עצמאי (900×700) שמשתמשים פותחים מתפריט "⋯" ברשימת התוספים; זה נהרס מקרוב. סביבת הדף וממשק ה-API של 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), בין אם השיחה מגיעה מה-AI, מסמל סרגל הכלים או מהפאנל שלך. אתה אף פעם לא צריך לבקש אותם.

typeמוצג בתורסוג defaultValue
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מנתחי מסמכים (documentParsers)

כאשר המשתמש מפיל קובץ לתיבת הקלט, המארח מחפש מנתחים שהוכרזו על ידי תוספים מופעלים לפי סוג MIME ומעביר את תוכן הקובץ כ-base64 ל-toolName התואם. זה לא כלי שה-AI מחליט לקרוא לו, אז תרשום גם לא את כלי הניתוח תחת 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)

לתהליך הפלאגין אין 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 }{}התוכן הוא 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מחזור חיים

שָׁלָבהִתְנַהֲגוּת
הַתחָלָהעצלן כברירת מחדל: לא הופעל עם האפליקציה, התפצל בקריאה הראשונה לאחד הכלים שלך (AI, סמל סרגל הכלים, חלונית, פקודה, ניתוח מסמכים). תוספים המכריזים על activationEvents: ["onStartupFinished"] מתחילים מיד לאחר סיום השקת האפליקציה; השתמש בזה רק עבור תוספים שצריכים טיימרים ברקע (תזכורות, סקרים), לא עבור תוספים של כלים רגילים.
תוֹשָׁבלאחר שהתחיל התהליך נשאר בחיים ונעשה בו שימוש חוזר בקריאות לכלים. אתה יכול לשמור מצב במטמון בזיכרון, אבל הנחה שניתן להפעיל אותו מחדש בכל עת.
לְהִתְרַסֵקאם התהליך יוצא באופן בלתי צפוי, המארח מפעיל אותו מחדש: מיד, ולאחר מכן לאחר 5 ו-15 שניות. לאחר 3 כישלונות רצופים הוא מסומן "התרסק" ולא נוסה שוב; משתמשים רואים את הסטטוס בדף הפלאגין. שיחות בטיסה כל שגיאות החזרה.
השבת / הסר / התקן מחדשהתהליך מסתיים ותצוגות מעוגנות ולוחות צפים נהרסים; התקנה מחדש מחליפה את כל התיקיה.
יומניםstdout/stderr שלך נכתבים לקובץ יומן האפליקציה עם קידומת מזהה הפלאגין. רגיל console.log מספיק לניפוי באגים; ראה "ניפוי באגים ושאלות נפוצות".
ENV
תהליך הילד מתחיל עם ELECTRON_RUN_AS_NODE=1, cwd היא תיקיית התקנת הפלאגין, וגרסת ה-Node תואמת את האלקטרון המצורף לאפליקציה. אל תסתמך על חבילה כלשהי המותקנת ברחבי העולם ואל תניח שקיים 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 → כלים → פלאגינים → כרטיסיית "Marketplace" → "פרסם תוסף" בפינה השמאלית העליונה, ולאחר מכן העלה את ה-zip. ההגשות נכנסות לבדיקה, אשר בודקת שהצהרת המניפסט תואמת לקוד (במיוחד הרשאות). לאחר האישור, משתמשים אחרים יכולים למצוא ולהתקין אותו בשוק, וה-AI יכול להתקין פלאגינים מאומתים עבור משתמשים באופן אוטומטי כאשר הוא רואה בהם צורך.

עדכונים

קפוץ version ופרסם שוב. האפליקציה משווה את הגרסה המותקנת לגרסת ה-marketplace ומבקשת לעדכן; התקנה מחדש שומרת על ערכי המצב וההגדרות המופעלים של המשתמש.

15דוגמה מלאה: Todo Quadrant

תוסף אמיתי ועובד (חתוך): ה-AI יכול להוסיף ולהסיר מטלות, סרגל הצד הימני מציג לוח שמתרענן בזמן אמת, והוא יכול לשלוח תזכורות למערכת. שרשרת שלושת אלה מכסה את פרוטוקול הכלי, דחיפות תצוגה מעוגנות ו-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איתור באגים ושאלות נפוצות

סִימפּטוֹםסיבה ותיקון
אימות המניפסט נכשל בהתקנהבדוק כל שדה מול טבלת "שדות הגילוי" כפי שההודעה מציינת: פורמט id, ראשי/ערך לא חייב להכיל .., הסמל חייב להיות ברשימת ההיתרים, פקודת חיבורי המקשים חייבת להצביע על כלי קיים בפקודות, רוחב בין 240 ל-640.
ה-AI אף פעם לא קורא לכלי שליכמעט תמיד בעיה של description: הטריגר לא ברור או שהוא לא כתוב באנגלית. ראה "כתיבת תיאור טוב". בדוק גם ששם הכלי לא מתנגש בכלי אחר.
זמן קצוב לשיחה (30 שניות)סקריפט הערך לא השיב עם tool_result. בדרך כלל requestId לא הוד בחזרה, ההודעה type מאויתת שגויה, או שהתסריט הושלך בהפעלה ויצא. חפש שורות עם קידומת [plugin:your-id] ביומן האפליקציה.
סטטוס הפלאגין מראה "התרסק"3 התחלות כושלות רצופות. בדרך כלל require של חבילה חסרה; הפעלת node index.js בתיקיית הפלאגין משחזרת אותו. לאחר התיקון, כבה את התוסף והדלק אותו שוב בדף הפלאגין.
הלוח נפתח ריקנתיב entry שגוי, או שגיאת JS בדף. הדף פועל בארגז חול ללא 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