توسعه‌دهندگان
ورود ناشر

راهنمای ساخت افزونه

این راهنما «چطور» را می‌گوید: افزونه چطور نصب می‌شود، چطور درخواست‌های کرسی را وارسی می‌کند، کرسی را چطور صدا می‌زند و صفحه‌هایش چطور در پوستهٔ کرسی باز می‌شوند. برای همهٔ فیلدهای manifest به مرجع manifest و برای یک نمونهٔ کامل به افزونهٔ نمونه سر بزنید.

۱. فایل manifest

همه چیزِ افزونه در korsi-plugin.yaml است و کرسی چیزی بیرون از آن را نمی‌پذیرد. پیش از ارسال، آن را با همان مدلی که هر instance می‌خواند بسنجید:

uv run python -m korsi_api.tools.check_plugin_manifest korsi-plugin.yaml

صفحهٔ ارسال نسخه همین پرتال هم manifest را پیش از ارسال با JSON Schema و با بررسی‌های کاتالوگ کرسی می‌سنجد و هر مشکل را کنار فیلد خودش نشان می‌دهد.

قاعده‌هایی که بیشتر از همه رد می‌کنند:

  • id به شکل reverse-DNS و با حروف کوچک است، مثل ir.acme.crm.

  • هر چیزی که استفاده می‌کنید، باید scopeاش را خواسته باشید: نوع رکورد records.own می‌خواهد، پیشنهاد proposals.*، ورود منبع sources.intake.*، و فروش پلن wallet.consume.

  • نرخ هر پلن فقط برای خدمت‌هایی است که در services اعلام شده‌اند.

  • base_url فقط برای external است و باید https باشد، به‌جز localhost در توسعه.

  • افزونه‌ای که کنار instance اجرا می‌شود (instance) به‌جای base_url این‌ها را می‌دهد:

    • image با digest؛
    • port که کانتینر روی آن HTTP گوش می‌دهد (پیش‌فرض 8080)؛
    • egress، یعنی همهٔ مقصدهای خروجی‌اش.

    آدرس را کرسی برای هر نصب جدا می‌سازد و همان را در lifecycle می‌فرستد. هر مقصدی غیر از این‌ها و خود کرسی بسته است.

  • اگر نسخهٔ جدید base_url یا egress را عوض کند، ادمین باید دوباره رضایت بدهد.

۲. نصب و اعتبارنامه

وقتی ادمین سازمان افزونه را نصب می‌کند، کرسی یک کاربر ماشینی برای آن نصب می‌سازد و به این آدرس خبر می‌دهد:

POST {base_url}/korsi/lifecycle
{
  "event": "installed",
  "installation_id": "…",
  "api_base": "https://<instance>/plugin/v1",
  "token": "…",
  "signing_secret": "…",
  "scopes": ["…"],
  "settings": {}
}
  • token اعتبارنامهٔ افزونه برای /plugin/v1 و سرور MCP کرسی است. آن را رمزشده نگه دارید.
  • signing_secret کلیدی است که کرسی هر رویداد و هر فراخوان ابزار را با آن امضا می‌کند.
  • برای اطمینان، با همان توکن GET {api_base}/installation را صدا بزنید.
  • {"event": "removed"} یعنی نصب حذف شده و توکن دیگر کار نمی‌کند.

نصب در حالت توسعه: وقتی کرسی به لپ‌تاپ شما دسترسی ندارد، اعتبارنامه تحویل داده نمی‌شود. ادمین آن را یک بار از صفحهٔ نصب می‌خواند («خواندن اعتبارنامه») و به شما می‌دهد. سه چیز است:

  • شناسهٔ نصب؛
  • توکن؛
  • signing_secret، که بدون آن نمی‌شود رویدادها و فراخوان‌های ابزار کرسی را وارسی کرد.

افزونهٔ نمونه آن را با email-commitments register می‌گیرد.

تحویل پس از ثبت: کرسی اعتبارنامه را فقط پس از ثبت کاربر ماشینی می‌فرستد. پس افزونه می‌تواند در جواب installed بی‌درنگ با همان توکن GET /installation را صدا بزند. اگر افزونه جواب ندهد، کرسی با همان توکن دوباره می‌فرستد.

۳. امضا

هر درخواستی که کرسی به افزونه می‌فرستد، این هدر را دارد:

Korsi-Signature: t=<unix>,v1=<hex>

v1 برابر است با HMAC-SHA256 روی "<t>.<body>" با signing_secret. امضای قدیمی‌تر از پنج دقیقه را رد کنید. تابع verify_signature در نمونه همین کار را می‌کند.

۴. صدا زدن کرسی

خواندن دادهٔ کرسی: سرور MCP

پرونده، افراد، جلسه، سند، تقویم و حافظه را از سرور MCP کرسی و با همان توکن بخوانید. فقط ابزارهایی را می‌بینید که scopeهای تأییدشده‌تان پوشش می‌دهند.

نوشتن: صفحهٔ افزونه (/plugin/v1)

مستندات OpenAPI آن در {api_base}/openapi.json است.

کارمسیر
خودم کیستمGET /installation
همکارانی که می‌شود پیشنهاد را به آن‌ها دادGET /people
رکوردهای خودمGET /records/{type}، GET/PUT/DELETE /records/{type}/{external_id}
پیشنهاد در رکوردهای کرسیPOST /proposals، GET /proposals
وارد کردن پیام یا سند برای بازبینیPOST /sources
کیف پولGET /wallet، POST /wallet/holds، …/settle، …/release، POST /wallet/consume
رویدادها با pollingGET /events?after=

نوشتن در رکوردهای کرسی همیشه پیشنهاد است. یک نفر آن را با کلیک خودش اعمال می‌کند، یا قاعده‌ای که سازمان برای نوع‌های کم‌خطر گذاشته است. جواب به شکل رویداد plugin.proposal.settled برمی‌گردد و اگر کسی دلیل رد نوشته باشد، آن دلیل هم همراهش است. شخص می‌تواند اول با یک کلیک رد کند و دلیل را بعداً بنویسد. در این حالت همان رویداد یک بار دیگر برای همان external_id و این بار با reason می‌رسد. آن را به‌روزرسانی بدانید، نه حکم تازه.

پول: پیش از هر خدمت رزرو کنید و بعد از آن تسویه. MU را کرسی از نرخ پلن فعال حساب می‌کند و افزونه فقط کلید خدمت و تعداد را می‌فرستد.

۵. رویدادها

POST {base_url}/korsi/events

رویدادها امضاشده و دست‌کم یک‌باره‌اند و Korsi-Event-Id دارند. اگر سرور افزونه از بیرون در دسترس نیست، همین جریان را با GET /events?after= بخوانید.

۶. ابزار برای کرسیار

POST {base_url}/korsi/tools/{name}

بدنه این‌هاست: installation_id، user_id، arguments و handle. با handle کرسی را به‌جای همان شخص بخوانید. هر چه از این راه ببینید، همان چیزی است که آن شخص می‌بیند. جواب را به شکل {"content": …} و در کمتر از ده ثانیه برگردانید. ابزار نباید چیزی را تغییر دهد.

۷. صفحه‌ها در پوستهٔ کرسی

ui.app و ui.panels داخل iframe و درون پوستهٔ کرسی باز می‌شوند. صفحه، Bridge را از همان کرسی‌ای که در آن اجرا می‌شود بار می‌کند:

const bridge = await import(`${korsiOrigin}/sdk/korsi-bridge.js`);
const context = await bridge.connect();   // زبان، جهت، تم، تقویم، شخص، رکورد زمینه
const handle = await bridge.getHandle();  // دستهٔ مهرشدهٔ همین شخص، با تمدید خودکار
  • با handle صفحهٔ افزونه را به‌جای همان شخص صدا بزنید.
  • دیالوگ‌های تأیید و انتخاب فرد یا پرونده را از Bridge بخواهید. این‌ها را خود کرسی می‌کشد.
  • پنل‌ها فقط وقتی بار می‌شوند که شخص خودش بازشان کند.
  • allowedOrigins را در connect بدهید و با هدر Content-Security-Policy: frame-ancestors <کرسی‌ها> فقط به کرسی اجازه دهید صفحه را قاب کند.
  • رنگ‌ها، حالت روشن یا تیره، فونت، جهت و زبان در korsi:init (و دوباره با هر تغییر) می‌رسد. افزونهٔ نمونه آن‌ها را به متغیرهای CSS تبدیل می‌کند تا صفحه شبیه خود کرسی باشد.

۸. افزونهٔ نمونه و اجرای محلی

مخزن korsi-plugin-email-commitments یک افزونهٔ کامل است:

  1. شخص متن ایمیل را در صفحهٔ آن داخل کرسی می‌گذارد.
  2. افزونه تعهدها را پیدا می‌کند.
  3. به‌جای همان شخص، ایمیل را منبع شخصی او می‌کند و هر تعهد همکار را به‌صورت کار پیشنهادی برای خودش می‌فرستد.
  4. برای هر گفتگو یک رکورد «رشتهٔ ایمیل» نگه می‌دارد و هزینه را از کیف پولش می‌دهد.

اجرای آن کنار یک کرسی محلی:

cd korsi-plugin-email-commitments && uv sync && uv run email-commitments serve --port 8787
cd korsi-api && uv run python -m korsi_api.tools.plugin_dev_release ../korsi-plugin-email-commitments/korsi-plugin.yaml

دستور دوم نسخه را مستقیم در کاتالوگ instance محلی می‌گذارد، بدون بازبینی. فقط بیرون از production کار می‌کند. سپس ادمین آن را از فروشگاه (/apps/plugins) نصب می‌کند و به کیف پولش MU می‌دهد. ../dev.sh افزونهٔ نمونه را هم با بقیه بالا می‌آورد.

۹. انتشار

  • افزونهٔ external: نسخه‌ای با base_url واقعی (https) را از صفحهٔ ارسال نسخه بفرستید.
  • افزونهٔ instance: image را در رجیستری کرسی (registry.korsi.ai) push کنید و در manifest با digest نام ببرید. فعلاً اعتبارنامهٔ push را تیم کرسی می‌دهد. رجیستری فقط یک حساب دارد و دسترسی جدا برای هر ناشر هنوز ساخته نشده است.