تخطَّ إلى المحتوى

النقل من pi-mono: دليل عملي للدمج

هذا الدليل عبارة عن قائمة تحقق قابلة للتكرار لنقل التغييرات من pi-mono إلى هذا المستودع. استخدمه لأي عملية دمج: ملف واحد، أو فرع ميزة، أو مزامنة إصدار كاملة.

الالتزام: b21b42d032919de2f2e6920a76fa9a37c3920c0a التاريخ: 2026-03-22

قم بتحديث هذا القسم بعد كل مزامنة؛ لا تعد استخدام النطاق السابق.

عند بدء مزامنة جديدة، قم بتوليد الرقع من هذا الالتزام فصاعداً:

Terminal window
git format-patch b21b42d032919de2f2e6920a76fa9a37c3920c0a..HEAD --stdout > changes.patch
  • حدد المرجع الأصلي (التزام، وسم، أو طلب سحب).
  • اسرد الحزم أو المجلدات التي تخطط للعمل عليها.
  • قرر أي الميزات ضمن النطاق وأيها يتم تخطيها عمداً.
  • فضّل فرقاً نظيفاً ومركّزاً بدلاً من النسخ الشامل.
  • تجنب نسخ المخرجات المبنية أو الملفات المولّدة.
  • إذا أضاف المصدر الأصلي ملفات جديدة، أضفها صراحةً وراجع محتوياتها.

2) طابق اتفاقيات امتدادات الاستيراد

Section titled “2) طابق اتفاقيات امتدادات الاستيراد”

معظم ملفات TypeScript التنفيذية تحذف .js في الاستيرادات الداخلية، لكن بعض نقاط الدخول للاختبارات/المعايير تحتفظ بـ .js لتوافق ESM في وقت التشغيل. اتبع النمط الموجود في الحزمة المحلية؛ لا تقم بإزالة الامتدادات بشكل شامل.

  • في ملفات التشغيل في packages/coding-agent، احتفظ بالاستيرادات الداخلية بدون امتداد ما لم تستورد أصولاً غير TS.
  • في packages/tui/test و packages/natives/bench، احتفظ بـ .js حيث تستخدمها الملفات المحيطة بالفعل.
  • احتفظ بامتدادات الملفات الحقيقية عندما تتطلبها الأدوات (مثل .json، .css، تضمينات نصوص .md).
  • مثال: import { x } from "./foo.js";import { x } from "./foo"; (فقط عندما تكون اتفاقية الحزمة بدون امتداد).

3) استبدل نطاقات الاستيراد

Section titled “3) استبدل نطاقات الاستيراد”

يستخدم المصدر الأصلي نطاقات حزم مختلفة. استبدلها بشكل متسق.

  • استبدل النطاقات القديمة بالنطاق المحلي المستخدم هنا.
  • أمثلة (عدّلها لتتوافق مع الحزم الفعلية التي تنقلها):
    • @mariozechner/pi-coding-agent@f5-sales-demo/xcsh
    • @mariozechner/pi-agent-core@f5-sales-demo/pi-agent-core
    • @mariozechner/pi-tui@f5-sales-demo/pi-tui
    • @mariozechner/pi-ai@f5-sales-demo/pi-ai

4) استخدم واجهات Bun حيث تتفوق على Node

Section titled “4) استخدم واجهات Bun حيث تتفوق على Node”

نحن نعمل على Bun. استبدل واجهات Node فقط عندما يوفر Bun بديلاً أفضل.

قم بالاستبدال:

  • تشغيل العمليات: child_process.spawn → Bun Shell $ للأوامر البسيطة، Bun.spawn/Bun.spawnSync للتدفق أو العمل طويل الأمد
  • إدخال/إخراج الملفات: fs.readFileSyncBun.file().text() / Bun.write()
  • عملاء HTTP: node-fetch، axiosfetch الأصلي
  • تجزئة التشفير: node:crypto → Web Crypto أو Bun.hash
  • SQLite: better-sqlite3bun:sqlite
  • تحميل المتغيرات البيئية: dotenv → يحمّل Bun ملف .env تلقائياً

لا تستبدل (هذه تعمل بشكل جيد في Bun):

  • os.homedir() — لا تستبدلها بـ Bun.env.HOME أو Bun.env.HOME أو القيمة الحرفية "~"
  • os.tmpdir() — لا تستبدلها بـ Bun.env.TMPDIR || "/tmp" أو مسارات مشفرة
  • fs.mkdtempSync() — لا تستبدلها ببناء المسار يدوياً
  • path.join()، path.resolve()، إلخ — هذه جيدة كما هي

نمط الاستيراد: استخدم بادئة node: مع استيرادات مساحة الأسماء فقط (لا استيرادات مسماة من node:fs أو node:path).

اتفاقيات Bun الإضافية:

  • فضّل Bun Shell $ للأوامر القصيرة غير المتدفقة؛ استخدم Bun.spawn فقط عندما تحتاج إلى إدخال/إخراج متدفق أو التحكم في العملية.
  • استخدم Bun.file()/Bun.write() للملفات و node:fs/promises للمجلدات.
  • تجنب فحوصات Bun.file().exists()؛ استخدم معالجة isEnoent في try/catch.
  • فضّل Bun.sleep(ms) على أغلفة setTimeout.

خطأ:

// BROKEN: env vars may be undefined, "~" is not expanded
const home = Bun.env.HOME || "~";
const tmp = Bun.env.TMPDIR || "/tmp";

صحيح:

import * as os from "node:os";
import * as fs from "node:fs";
import * as path from "node:path";
const configDir = path.join(os.homedir(), ".config", "myapp");
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "myapp-"));

5) فضّل تضمينات Bun (بدون نسخ)

Section titled “5) فضّل تضمينات Bun (بدون نسخ)”

لا تنسخ أصول وقت التشغيل أو ملفات المورّدين في وقت البناء.

  • إذا كان المصدر الأصلي ينسخ الأصول إلى مجلد dist، استبدلها بتضمينات متوافقة مع Bun.
  • الموجّهات هي ملفات .md ثابتة؛ استخدم استيرادات نصوص Bun (with { type: "text" }) و Handlebars بدلاً من سلاسل الموجّهات المضمنة.
  • استخدم import.meta.dir + Bun.file لتحميل الموارد المجاورة غير النصية.
  • احتفظ بالأصول في المستودع ودع المجمّع يضمّنها.
  • تخلص من سكربتات النسخ ما لم يطلبها المستخدم صراحةً.
  • إذا كان المصدر الأصلي يقرأ ملفاً احتياطياً مجمّعاً في وقت التشغيل، استبدل قراءات نظام الملفات باستيراد تضمين نصي من Bun.
    • مثال (احتياطي تعليمات Codex):
      • const FALLBACK_PROMPT_PATH = join(import.meta.dir, "codex-instructions.md"); -> تمت إزالته
      • import FALLBACK_INSTRUCTIONS from "./codex-instructions.md" with { type: "text" };
      • استخدم return FALLBACK_INSTRUCTIONS; بدلاً من readFileSync(FALLBACK_PROMPT_PATH, "utf8")

تعامل مع package.json كعقد. ادمج بشكل مقصود.

  • احتفظ بـ name و version و type و exports و bin الحاليين ما لم يتطلب النقل تغييرات.
  • استبدل سكربتات npm/node ببدائل Bun (مثل bun check، bun test).
  • تأكد من أن التبعيات تستخدم النطاق الصحيح.
  • لا تخفّض إصدارات التبعيات لإصلاح أخطاء الأنواع؛ قم بالترقية بدلاً من ذلك.
  • تحقق من روابط حزم مساحة العمل و peerDependencies.

7) وحّد أسلوب الكود والأدوات

Section titled “7) وحّد أسلوب الكود والأدوات”
  • حافظ على اتفاقيات التنسيق الحالية.
  • لا تُدخل any ما لم يكن مطلوباً.
  • تجنب الاستيرادات الديناميكية واستيرادات الأنواع المضمنة؛ استخدم استيرادات المستوى الأعلى فقط.
  • لا تبنِ الموجّهات في الكود أبداً؛ الموجّهات هي ملفات .md ثابتة يتم عرضها باستخدام Handlebars.
  • في coding-agent، لا تستخدم console.log/console.warn/console.error أبداً؛ استخدم logger من @f5-sales-demo/pi-utils.
  • استخدم Promise.withResolvers() بدلاً من new Promise((resolve, reject) => ...).
  • لا تستخدم الكلمات المفتاحية private/protected/public على حقول الفئة أو الطرق. استخدم حقول ES الخاصة # للتغليف؛ اترك الأعضاء القابلة للوصول بدون كلمة مفتاحية. الاستثناء الوحيد هو خصائص معاملات المُنشئ (constructor(private readonly x: T))، حيث تكون الكلمة المفتاحية مطلوبة بواسطة TypeScript. عند نقل كود المصدر الأصلي الذي يستخدم private foo أو protected bar، حوّلها إلى #foo (خاص) أو bar بدون كلمة مفتاحية (قابل للوصول).
  • فضّل المساعدات والأدوات الموجودة على الكود الجديد المخصص.
  • حافظ على تغييرات البنية التحتية الموجهة لـ Bun التي تم إجراؤها بالفعل في هذا المستودع:
    • وقت التشغيل هو Bun (لا نقاط دخول Node).
    • مدير الحزم هو Bun (لا ملفات قفل npm).
    • واجهات Node الثقيلة (child_process، readline) مستبدلة ببدائل Bun.
    • واجهات Node الخفيفة (os.homedir، os.tmpdir، fs.mkdtempSync، path.*) محفوظة.
    • سطور shebang لـ CLI تستخدم bun (ليس node، ليس tsx).
    • الحزم تستخدم ملفات المصدر مباشرة (لا خطوة بناء TypeScript).
    • سير عمل CI يشغّل Bun للتثبيت/الفحص/الاختبار.

8) أزل طبقات التوافق القديمة

Section titled “8) أزل طبقات التوافق القديمة”

ما لم يُطلب ذلك، أزل وسائط التوافق الأصلية.

  • احذف الواجهات القديمة التي تم استبدالها.
  • حدّث جميع مواقع الاستدعاء للواجهة الجديدة مباشرة.
  • لا تحتفظ بنسخ *_v2 أو نسخ متوازية.

9) حدّث التوثيق والمراجع

Section titled “9) حدّث التوثيق والمراجع”
  • استبدل روابط مستودع pi-mono حيثما كان مناسباً.
  • حدّث الأمثلة لاستخدام Bun ونطاقات الحزم الصحيحة.
  • تأكد من أن تعليمات README لا تزال تتوافق مع سلوك المستودع الحالي.

شغّل الفحوصات القياسية بعد التغييرات:

  • bun check

إذا كان المستودع يحتوي بالفعل على فحوصات فاشلة غير مرتبطة بتغييراتك، أشر إلى ذلك. الاختبارات تستخدم مشغّل Bun (ليس Vitest)، لكن شغّل bun test فقط عند الطلب صراحةً.

11) احمِ الميزات المحسّنة (قائمة فخ الانحدار)

Section titled “11) احمِ الميزات المحسّنة (قائمة فخ الانحدار)”

إذا كنت قد حسّنت السلوك محلياً بالفعل، تعامل مع تلك التحسينات على أنها غير قابلة للتفاوض. قبل النقل، دوّن التحسينات وأضف فحوصات صريحة حتى لا تضيع في الدمج.

  • جمّد السلوك المتوقع: أضف ملاحظة قصيرة “قبل/بعد” لكل تحسين (المدخلات، المخرجات، القيم الافتراضية، الحالات الحدية). هذا يمنع التراجع الصامت.
  • خريطة القديم → الجديد للواجهات: إذا أعاد المصدر الأصلي تسمية المفاهيم (hooks → extensions، custom tools → tools، إلخ)، تأكد من أن كل نقطة دخول قديمة لا تزال متصلة. علم أو تصدير واحد مفقود يعني وظائف مفقودة.
  • تحقق من التصديرات: تحقق من exports في package.json، والأنواع العامة، وملفات barrel. عمليات النقل الأصلية غالباً تنسى إعادة تصدير الإضافات المحلية.
  • غطِّ المسارات غير السعيدة: إذا أصلحت معالجة الأخطاء، أو المهل الزمنية، أو منطق الاحتياط، أضف اختباراً أو على الأقل قائمة تحقق يدوية تمارس تلك المسارات.
  • تحقق من الافتراضيات وترتيب دمج التكوين: التحسينات غالباً تعيش في الافتراضيات. تأكد من أن الافتراضيات الجديدة لم تتراجع (مثل أسبقية التكوين الجديدة، الميزات المعطلة، قوائم الأدوات).
  • دقق سلوك البيئة/الصدفة: إذا أصلحت التنفيذ أو العزل، تحقق من أن المسار الجديد لا يزال يستخدم بيئتك المنقّحة ولا يعيد تقديم تجاوزات الأسماء المستعارة/الدوال.
  • أعد تشغيل عينات مستهدفة: احتفظ بمجموعة أدنى من الأمثلة “المعروفة بأنها جيدة” وشغّلها بعد النقل (أعلام CLI، تسجيل الإضافات، تنفيذ الأدوات).

12) اكتشف وتعامل مع الكود المُعاد هيكلته

Section titled “12) اكتشف وتعامل مع الكود المُعاد هيكلته”

قبل نقل ملف، تحقق مما إذا كان المصدر الأصلي قد أعاد هيكلته بشكل كبير:

Terminal window
# Compare the file you're about to port against what you have locally
git diff HEAD upstream/main -- path/to/file.ts

إذا أظهر الفرق أن الملف تمت إعادة هيكلته (ليس مجرد ترقيع):

  • تجريدات جديدة، مفاهيم مُعاد تسميتها، وحدات مدمجة، تدفق بيانات متغير

فيجب عليك قراءة التنفيذ الجديد بالكامل قبل النقل. الدمج الأعمى للكود المُعاد هيكلته يفقد الوظائف لأن:

ملاحظة: تم مؤخراً تقسيم الوضع التفاعلي إلى controllers/utils/types. عند نقل التغييرات المرتبطة بأثر رجعي، انقل التحديثات إلى الملفات الفردية التي أنشأناها وتأكد من بقاء توصيل interactive-mode.ts متزامناً.

  1. الافتراضيات تتغير بصمت - متغير جديد defaultFoo = [a, b] قد يستبدل getAllFoo() القديم الذي كان يعيد [a, b, c, d, e].

  2. خيارات الواجهة تُسقط - عندما تندمج الأنظمة (مثل hooks + customToolsextensions)، قد لا تتصل الخيارات القديمة بالتنفيذ الجديد.

  3. مسارات الكود تصبح قديمة - مفهوم مُعاد تسميته (مثل hookMessagecustom) يحتاج تحديثات في كل عبارة switch، وحارس نوع، ومعالج—ليس فقط التعريف.

  4. السياق/القدرات تتقلص - الواجهات القديمة ربما كشفت { logger, typebox, pi } التي نسيت الواجهات الجديدة تضمينها.

عندما يعيد المصدر الأصلي هيكلة وحدة:

  1. اقرأ التنفيذ القديم - افهم ماذا كان يفعل، ما الخيارات التي قبلها، ما الذي كشفه.

  2. اقرأ التنفيذ الجديد - افهم التجريدات الجديدة وكيف تتوافق مع السلوك القديم.

  3. تحقق من تكافؤ الميزات - لكل قدرة في الكود القديم، تأكد من أن الكود الجديد يحافظ عليها أو يزيلها صراحةً.

  4. ابحث عن المتبقيات - ابحث عن الأسماء/المفاهيم القديمة التي ربما فاتت في عبارات switch، والمعالجات، ومكونات الواجهة.

  5. اختبر الحدود - أعلام CLI، خيارات SDK، معالجات الأحداث، القيم الافتراضية—هذه هي حيث تختبئ الانحدارات.

Terminal window
# Find all uses of an old concept that may need updating
rg "oldConceptName" --type ts
# Compare default values between versions
git show upstream/main:path/to/file.ts | rg "default|DEFAULT"
# Check if all enum/union values have handlers
rg "case \"" path/to/file.ts

13) قائمة تحقق التدقيق السريع

Section titled “13) قائمة تحقق التدقيق السريع”

استخدم هذه كمرور نهائي قبل الانتهاء:

عند التزام نقل بأثر رجعي، اتبع صيغة المستودع <type>(scope): <past-tense description> واحتفظ بنطاق الالتزامات في العنوان.

fix(coding-agent): backported pi-mono changes (<from>..<to>)
packages/<package>:
- <type>: <description>
- <type>: <description> (#<issue> by @<contributor>)
packages/<other-package>:
- <type>: <description>

مثال:

fix(coding-agent): backported pi-mono changes (9f3eef65f..52532c7c0)
packages/ai:
- fix: handle "sensitive" stop reason from Anthropic API
- fix: normalize tool call IDs with special characters for Responses API
- fix: add overflow detection for Bedrock, MiniMax, Kimi providers
- fix: 429 status is rate limiting, not context overflow
packages/tui:
- fix: refactored autocomplete state tracking
- fix: file autocomplete should not trigger on empty text
- fix: configurable autocomplete max visible items
- fix: improved table column width calculation with word-aware wrapping
packages/coding-agent:
- fix: preserve external config.yml edits on save (#1046 by @nicobailonMD)
- fix: resolve macOS NFD and curly quote variants in file paths

القواعد:

  • جمّع التغييرات حسب الحزمة
  • استخدم أنواع الالتزام التقليدية (fix، feat، refactor، perf، docs)
  • ضمّن أرقام المشاكل/طلبات السحب الأصلية ونسبة المساهمين للمساهمات الخارجية
  • نطاق الالتزامات في العنوان يساعد في تتبع نقاط المزامنة

يحتوي فرعنا على قرارات معمارية تختلف عن المصدر الأصلي. لا تنقل هذه الأنماط الأصلية:

المصدر الأصليفرعناالسبب
فئة FooterDataProviderStatusLineComponentسطر حالة أبسط ومتكامل
ctx.ui.setHeader() / ctx.ui.setFooter()وسيط فارغ في الأوضاع غير TUIمُنفّذ في TUI، بدون عملية في غيره
ctx.ui.setEditorComponent()وسيط فارغ في الأوضاع غير TUIمُنفّذ في TUI، بدون عملية في غيره
كائن خيارات InteractiveModeOptionsمعاملات مُنشئ موضعية (نوع الخيارات لا يزال مُصدّراً)حافظ على توقيع المُنشئ؛ حدّث النوع عندما يضيف المصدر الأصلي حقولاً
المصدر الأصليفرعنا
extension-input.tshook-input.ts
extension-selector.tshook-selector.ts
ExtensionInputComponentHookInputComponent
ExtensionSelectorComponentHookSelectorComponent
المصدر الأصليفرعناملاحظات
sessionManager.appendSessionInfo(name)sessionManager.setSessionName(name)نستخدم sessionName في كل مكان
sessionManager.getSessionName()sessionManager.getSessionName()نفسه (وحّدنا ليتوافق مع RPC الأصلي)
agent.sessionName / setSessionName()agent.sessionName / setSessionName()نفسه
المصدر الأصليفرعناالسبب
clipboard.ts + clipboard-image.ts (ملفات أدوات)وحدة الحافظة في @f5-sales-demo/pi-nativesمدمجة في تنفيذ N-API الأصلي
المصدر الأصليفرعنا
vitest مع vi.mock()bun:test مع vi من bun
تأكيدات node:testمطابقات expect()
المصدر الأصليفرعناملاحظات
createTool(cwd: string, options?)createTools(session: ToolSession) عبر سجل BUILTIN_TOOLSمصانع الأدوات تقبل ToolSession ويمكن أن تعيد null
واجهات *Operations لكل أداةواجهات كل أداة تبقى (FindOperations، GrepOperations)تُستخدم لتجاوزات SSH/البعيد
fs/promises في Node.js في كل مكانBun.file()/Bun.write() للملفات؛ node:fs/promises للمجلداتفضّل واجهات Bun عندما تبسّط
المصدر الأصليفرعناملاحظات
proper-lockfile + auth.jsonagent.db (bun:sqlite)بيانات الاعتماد مخزنة حصرياً في agent.db
بيانات اعتماد واحدة لكل مزوّدبيانات اعتماد متعددة مع اختيار دوريمنطق تقارب الجلسة والتراجع محفوظ
المصدر الأصليفرعنا
jiti لتحميل TypeScriptimport() الأصلي في Bun
حقل pkg.pi في البيانpkg.xcsh ?? pkg.pi (فضّل مساحة أسمائنا)

تخطَّ هذه الميزات الأصلية

Section titled “تخطَّ هذه الميزات الأصلية”

عند النقل، تخطَّ هذه الملفات/الميزات بالكامل:

  • footer-data-provider.ts — نستخدم StatusLineComponent
  • clipboard-image.ts — الحافظة في وحدة N-API في @f5-sales-demo/pi-natives
  • ملفات سير عمل GitHub — لدينا CI خاص بنا
  • models.generated.ts — مولّد تلقائياً، أعد توليده محلياً (كـ models.json بدلاً من ذلك)

هذه موجودة في فرعنا ولكن ليست في المصدر الأصلي. لا تكتب فوقها أبداً:

  • StatusLineComponent في الوضع التفاعلي
  • مصادقة متعددة بيانات الاعتماد مع تقارب الجلسة
  • نظام الاكتشاف القائم على القدرات (defineCapability، registerProvider، loadCapability، skillCapability، إلخ)
  • تكاملات MCP/Exa/SSH
  • الكتابة المباشرة عبر LSP للتنسيق عند الحفظ
  • اعتراض Bash (checkBashInterception)
  • اقتراحات المسارات الضبابية في أداة القراءة