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

أنواع خطوات خط الأنابيب

لخطوة خط الأنابيب محوران مستقلان:

  • النوع (StepKind) — كيف يجدول المحرّك الخطوة بالنسبة إلى مشغّلاتها.
  • مفتاح الجسم (BuiltInBodyKeys) — أي دالة مغلقة مسجّلة للجسم تنفّذ عمل الخطوة.

معرّفة في packages/cc_domain/lib/features/pipelines/domain/entities/step_kind.dart.

النوع دلالات الجدولة
trigger نقطة دخول إلزامية — واحدة بالضبط لكل قالب، وهي دائمًا العقدة الأولى. لا تؤدي عملًا بنفسها؛ ما يبدأ التشغيل (يدوي / حدث / جدولة) يُتتبَّع منفصلًا في صفوف PipelineTrigger. جسمها هو pipeline.trigger الذي لا يفعل شيئًا.
listen تنطلق حين تكتمل كل الخطوات المصدر (في StepTrigger.sourceStepIds).
join تنطلق حين تبلغ كل الخطوات في waitForStepIds حالة نهائية.
router تفريع شرطي — يعيد الجسم StepResult.route(key)، فيُطلق الحافة التالية التي يطابق routeKey الخاص بها فقط؛ وتُعلَّم الفروع غير المختارة متخطاة.
forEach تُجدول مثل listen (تنطلق حين تكتمل كل sourceStepIds). جسم flow.forEach المسجّل هو ما يكرّر؛ والمحرّك لا ينشئ خطوة ابنة لكل عنصر.
terminal حارس للمجدول بلا جسم. يكتمل تشغيل خط الأنابيب حين تنتهي خطوة terminal.

دوال مغلقة مسجّلة للجسم، مفاتيحها ثوابت BuiltInBodyKeys (packages/cc_domain/lib/features/pipelines/domain/templates/builtin_template_seeds.dart). عددها 25، وكلها مدرجة أدناه. تُقرأ التهيئة من PipelineNodeConfig الخاص بالخطوة (انظر أدناه) ما لم يُذكر غير ذلك؛ وتُقرأ «مفاتيح الحالة» من حالة خط الأنابيب / حمولة المشغّل وقت التنفيذ.

خطوة ليس bodyKey الخاص بها مسجّلًا تُصدر تحذيرًا عند تحميل القالب ثم لا تُنفَّذ — ولا تُفشل التشغيل. خطوتا trigger وterminal مستثنيتان من هذا التحذير: المشغّل يظل يشغّل جسم pipeline.trigger الذي لا يفعل شيئًا؛ وخطوة terminal بلا جسم.

جسم لا يفعل شيئًا لعقدة trigger الإلزامية — يكتمل فورًا حتى ينتشر المحرّك إلى المستمعات التالية. بلا تهيئة.

خطوة صدفة بلا وكيل (bash -c). تُستبدَل مواضع {{key}} في السكربت من الحالة + حمولة المشغّل بقيم مُهرَّبة للصدفة.

حقل الإعداد الوصف
script أمر الصدفة المطلوب تنفيذه (مطلوب)
outputKey مفتاح الحالة الذي يستقبل stdout بعد قص المسافات عند الخروج 0

تعمل بدليل العمل <cc_root>/pipelines/<pipelineRunId>/ (مشترك بين كل خطوات bash في التشغيل) ومع GITHUB_TOKEN في البيئة. وتكتب أيضًا <stepId>_runDir في الحالة. الخروج بغير صفر يُفشل الخطوة بذيل stderr.

عقدة عامة للموجّه والإرسال: تصيغ الموجّه، وترسل الوكيل إلى محادثة، وتُعلَّق حتى ينتهي التشغيل. تُستخلَص حمولة submit_output الخاصة بالوكيل في الحالة تحت outputKey.

حقل الإعداد الوصف
agentId معرّف UUID لوكيل ضمن نطاق مساحة العمل يُرسَل (مطلوب)
prompt نص التعليمات؛ يدعم استبدال {{key}} (مطلوب)
outputKey مفتاح الحالة للمخرج المستخلَص
outputSchema JSON Schema يجب أن يحققه المخرج
label تسمية بشرية تُعرض على اللوحة
extras.spaceId محادثة قائمة يُنجَز العمل فيها (الافتراضي: محادثة مخفية)
extras.conversationTitle مجرى مسمّى داخل تلك المساحة (اختياري)
extras.mode يُقرأ على العقدة التي تفتح الغرفة (messaging.createSpace)، لا هنا. الافتراضي review.

جسم موجّه — يقرأ config.extras، ويقيّم شرطًا، ويعيد StepResult.route(key). الشروط ليست تعبيرات JavaScript؛ وتُدعَم ثلاثة أشكال للتأليف، بترتيب الأولوية:

  • شجرة محمولات (extras.predicate) — شجرة منطقية توجّه "true" / "false". كل عقدة خريطة فيها type:
    • {"type": "fileExists", "paths": [...], "baseKey": "repo_local_path", "negate": false, "recursive": false} — تتحقق حين يوجد أي مسار من القائمة على القرص؛ negate يعكسها؛ recursive يبحث أيضًا في الأدلة الفرعية (متخطيًا .git وnode_modules وbuild و.dart_tool). تُحَل المسارات النسبية مقابل state[baseKey] (الافتراضي repo_local_path)، وإلا فدليل مساحة العمل الخاص بالتشغيل.
    • {"type": "comparison", "left": "{{score}}", "op": "gt", "right": 80} — المعاملات equals وnotEquals وcontains وexists وnotExists وgt وlt؛ تقرأ حالة خط الأنابيب، لا نظام الملفات.
    • {"type": "and" | "or", "of": [<predicate>, ...]} — مجموعات منطقية.
    • {"type": "not", "of": <predicate>} — نفي.
  • تفريع (extras.switchKey) — {"switchKey": "pr_class", "cases": [...], "default": "standard"}؛ يوجّه إلى أول حالة تحتويها قيمة الحالة بلا حساسية لحالة الأحرف، وإلا default.
  • مقارنة (المستوى الأعلى القديم extras.left / extras.op / extras.right) — تعادل محمول comparison، وتُبقى للقوالب التي أُلِّفت قبل الشجرة.

تحمل الحواف الخارجة من العقدة routeKey يجب أن يطابق المفتاح المعاد.

ينشر النتائج المجمَّعة تعليق مراجعة على طلب السحب عبر عميل طلبات السحب في GitHub.

مفتاح الحالة الوصف
repo_full_name owner/repo (مطلوب)
pr_number رقم طلب السحب — عدد صحيح أو سلسلة رقمية (مطلوب)
consolidated_findings متن التعليق (مطلوب)

يعيد StepResult.terminal مع comment_review_id وcommented_at في الحالة.

ينشر رسالة في مساحة مراسلة عبر MessagingPort.

مفتاح الحالة الوصف
space_id المساحة المستهدفة (مطلوب)
content متن الرسالة، يُقرأ حرفيًا من الحالة (مطلوب)

يكتب posted_space_id وposted_at في الحالة.

يرسل فريقًا كاملًا بدل وكيل واحد، ثم يُعلَّق حتى تنتهي تشغيلات الأعضاء.

حقل الإعداد الوصف
teamId فريق ضمن نطاق مساحة العمل يُرسَل (مطلوب؛ لا يجتمع مع agentId)
prompt نص الهدف؛ يدعم استبدال {{key}} (مطلوب)
dispatchMode allParallel (الافتراضي — مهمة لكل عضو) أو manager (يُرسَل القائد فقط لينسّق)
outputKey مفتاح الحالة لمخرجات الأعضاء المستخلَصة
outputSchema, label, extras.spaceId كما في conversation.promptAgent

بوابة موافقة. ترسل وكيل الاعتماد إلى محادثة (وضع المراجعة) مع موجّه البوابة وعقد مخرج {decision, reason}، ثم تُعلَّق حتى يسلّم المعتمِد عبر submit_output.

حقل الإعداد الوصف
agentId وكيل الاعتماد (مطلوب)
prompt موجّه البوابة (اختياري؛ يُستخدَم افتراضي عند غيابه)
outputKey مفتاح الحالة لحمولة {decision, reason} المستخلَصة
outputSchema يفتَرض مخطط موافقة (decision: approved / rejected، وreason)
label, extras.spaceId كما في conversation.promptAgent

تُحسم البوابة عبر submit_output فقط. يسمّي BuiltInBodyKeys.humanGate ومكتبة العقد ونص موجّه أحد القوالب المضمّنة أداتي MCP approve_step وreject_step؛ ولا توجد أي من الأداتين في أي حزمة أو سجل.

يزيل أشجار العمل المعزولة القديمة؛ ويختار نمطه من حمولة المشغّل. يلتزم بعلامة dryRun الخاصة بالتشغيل.

مفتاح الحالة الوصف
ticket_id يزيل أشجار عمل تلك التذكرة
repo_full_name + pr_number يزيل شجرة عمل محرّر طلب السحب المؤقتة
space_id يفكّك أشجار عمل تلك المحادثة ومجلدها
(لا شيء مما سبق) يمسح مساحة العمل: الأدلة المختفية، والمساحات الميتة، ومجلدات المحادثات اليتيمة

يستقبل outputKey (اختياري) سلسلة ملخص.

تعيين / انتشار على مجموعة في الحالة: يصيغ الموجّه مرة لكل عنصر، ثم يرسل الوكيل مرة واحدة بهذه الموجّهات مضمومة (فواصل ---) ويُعلَّق حتى ينتهي ذلك التشغيل. المجموعة الفارغة تكتمل فورًا بقائمة فارغة. ليس هذا إرسالًا متوازيًا لكل عنصر.

حقل الإعداد الوصف
agentId الوكيل الذي يُرسَل لكل عنصر (مطلوب)
prompt موجّه لكل عنصر؛ يدعم استبدال {{key}} (مطلوب)
extras.iterableKey مفتاح الحالة الذي يحمل المجموعة (مطلوب)
extras.itemKey المفتاح الذي يُربَط به العنصر الحالي في الموجّه (الافتراضي item)
outputKey مفتاح الحالة للمخرج المستخلَص (إرسال واحد، لا قائمة)

يشغّل قالب خط أنابيب آخر كخطوة فرعية متداخلة (يعمل خط الأنابيب الفرعي تشغيلًا ابنًا مع ضبط parentPipelineRunId). تُعلَّق الخطوة حتى يبلغ الابن حالة نهائية، ثم تُدمَج الحالة النهائية للابن تحت outputKey.

حقل الإعداد الوصف
extras.templateId القالب الابن المطلوب تشغيله (مطلوب؛ لا يستطيع خط الأنابيب استدعاء نفسه)
inputKeys مفاتيح الحالة المنسوخة إلى حمولة مشغّل الابن
outputKey مفتاح الحالة للحالة النهائية المدمجة للابن

فهرسة tree-sitter في الخلفية: يمشي مستودعًا، ويستخرج الرموز والحواف في عوازل العمال، ويُدخلها في مخطط الشفرة لمساحة العمل. يبث التقدّم في صف تشغيل الخطوة؛ ويدعم التشغيل التجريبي. tree-sitter وقواعده النحوية مكتبات أصلية مطلوبة — غياب dylib يعني أن الخادم لم يُقلِع، وقاعدة نحوية تفشل في الحل أثناء التشغيل تُفشل الخطوة بدل تخطيها.

مفتاح الحالة الوصف
repo_id المستودع المطلوب فهرسته (مطلوب)
repo_local_path المسار المحلي للنسخة (مطلوب)

تمييز المتحدثين بلا اتصال. يقرأ الصوت المحتفَظ به للاجتماع، ويجمّعه في متحدثين (الشخص 1، الشخص 2، …)، ويعيد تسمية مقاطع النص، ويعيد كتابة حالة transcript؛ ويُصدر أيضًا diarization_spans لخطوة meeting.updateTranscript المتوازية. يمرّر النص كما هو حين لا يُحتفَظ بصوت أو حين لا تكون النماذج مثبّتة.

مفتاح الحالة الوصف
meeting_id الاجتماع المطلوب تمييز متحدثيه (مطلوب)

meeting.saveNotes, meeting.addActionItems, meeting.addDecisions

قسم بعنوان “meeting.saveNotes, meeting.addActionItems, meeting.addDecisions”

أجسام حفظ حتمية لملخص الاجتماع. يقرأ كل منها meeting_id وحمولة meeting_outcome المنظَّمة لخطوة الوكيل ({summary, enhancedNotes, actionItems[], decisions[]}) من الحالة ويكتب جزأه في جدوله — الملاحظات، أو بنود الإجراءات، أو القرارات. لا تُمسح الصفوف المحفوظة سابقًا في تشغيل متدهور.

مفتاح الجسم الوصف
meeting.identifySpeakers التعرّف على المتحدثين عبر الاجتماعات: يطابق المتحدثين المميَّزين مع ملفات الصوت المحفوظة ويطبّق المطابقات الواثقة تلقائيًا. لا يفعل شيئًا بلا ملفات صوت أو تضمينات.
meeting.updateTranscript يطبّق تسميات الشخص N من diarization_spans ويدمج أجزاء كل نافذة في أدوار لكل متحدث، ثم يحفظ النص المنظَّف. لا يفعل شيئًا حين لا ينتج التمييز شيئًا.
meeting.assemblePlayback يجمّع مسار التشغيل المختلط للاجتماع من ملفات WAV المحتفَظ بها لكل قناة. لا يفعل شيئًا حين لا يُحتفَظ بصوت.
orchestration.markPhase في نهاية مخطط DAG للعمل، يكتب حراس فشل للتذاكر الفرعية التي بلا مخرج ويقلب التنسيق إلى synthesizing.
orchestration.persistDeliverable يكتب مخرج التركيب في التذكرة الأم، ويكملها، وينشر المُخرَج، ويعلّم التنسيق completed.
orchestration.awaitApproval بوابة موافقة جزئية: تكتمل فورًا حين يكون مفتاح عقدة الخطوة ضمن مجموعة التنسيق المعتمدة، وإلا تُعلَّق حتى تستأنفها موافقة لاحقة. هذا الجسم الوحيد الذي يضبط extras.awaitApproval، وهو ما يعفيه من مهلة الـ 24 ساعة للخطوة المعلّقة.
messaging.createSpace يفتح المحادثة التي يعمل فيها بقية القالب، وتُنشَر تحت outputKey الخاص بالخطوة (القوالب المضمّنة تستخدم pipeline_space_id). قائمة repoIds الفارغة لا تسحب شيئًا؛ وextras['allRepos'] يسحب كل مستودع في مساحة العمل. extras['createConversation'] (مطفأ افتراضيًا) يفتح أيضًا مجرًى مسمّى. خطوة الوكيل تنضم إلى غرفة ولا تفتح واحدة أبدًا، فانتشار بلا هذه العقدة يفشل عند الإرسال — ووصلها مرة واحدة يعني أن الانتشار كله يشترك في نسخة واحدة بدل تجهيز نسخة لكل واحد.
prReview.finalize الخطوة الأخيرة في قالب مراجعة طلب السحب: تفرز عقد المراجعة المتراكمة في مجموعات إجماع وتحسب الحكم لكل طلب سحب.
skills.analyze يشغّل فحص سلسلة توريد المهارات على المهارات المثبّتة في مساحة العمل ويسجّل كل حكم.

يعيد جسم الخطوة StepResult (packages/cc_domain/lib/features/pipelines/domain/entities/step_result.dart). تقبل كل المصانع خريطة mutatedState اختيارية تُدمَج في حالة خط الأنابيب، باستثناء failed.

المصنع التوقيع الوصف
ok StepResult.ok({mutatedState}) اكتمال عادي؛ تُقيَّم المستمعات التالية
route StepResult.route(nextRouterKey, {mutatedState}) اكتمال الموجّه؛ يختار الفرع التالي الذي يطابق routeKey الخاص به
suspendUntilEvent StepResult.suspendUntilEvent(eventType, {mutatedState}) يتوقف حتى يُطلَق نوع معيّن من أحداث النطاق
suspendUntilTasksComplete StepResult.suspendUntilTasksComplete(taskIds, {mutatedState}) يتوقف حتى تبلغ كل المهام المدرجة حالة نهائية
terminal StepResult.terminal({mutatedState}) اكتمل تشغيل خط الأنابيب — لا خطوات بعده
failed StepResult.failed(errorMessage) فشلت الخطوة برسالة خطأ

سلوك إعادة المحاولة لجسم عقدة فاشلة (PipelineNodeConfig.retryPolicy؛ القيمة null تعطّل الإعادة).

الحقل النوع الوصف
maxAttempts int مجموع المحاولات بما فيها الأولى (3 = محاولة + محاولتا إعادة)؛ ويجب أن يكون ≥ 1
backoff String linear أو exponential (الافتراضي)
initialDelayMs int الإمهال قبل أول إعادة، بالمللي ثانية؛ وتنمو الإمهالات اللاحقة حسب backoff

تهيئة لكل عقدة تُحمَل داخل تعريف الخطوة (packages/cc_domain/lib/features/pipelines/domain/entities/pipeline_node_config.dart). تشترك العقد المضمّنة والمخصّصة في هذا الشكل؛ ويقرأ كل جسم الحقول التي تهمه فقط.

الحقل النوع الوصف
prompt String? قالب موجّه مع استبدال {{key}}
script String? متن سكربت Bash مع استبدال {{key}}
agentId String? معرّف UUID لوكيل ضمن نطاق مساحة العمل يُرسَل
inputKeys List<String> مفاتيح الحالة التي تستهلكها هذه العقدة مدخلًا
repoIds List<String> المستودعات التي تسحبها عقدة messaging.createSpace (<repoId> أو <repoId>@<branch>). الفراغ = لا شيء؛ extras['allRepos'] = كل مستودع في مساحة العمل. يُتجاهَل على خطوات الوكيل.
outputKey String? مفتاح الحالة الذي يُكتَب تحته مخرج هذه العقدة
label String? تسمية بشرية تُعرض على اللوحة (الافتراضي معرّف الخطوة)
outputSchema Map<String, dynamic>? JSON Schema (مجموعة جزئية) يجب أن تحققها قيمة المخرج
reducer String? استراتيجية الدمج حين تكتب الفروع المتوازية outputKey نفسه: append أو mergeLists أو mergeMaps أو sum أو override (الافتراضي)
retryPolicy StepRetryPolicy? سياسة إعادة المحاولة عند فشل الجسم؛ null = محاولة واحدة
continueOnFail bool حين تكون true، لا يُفشل الفشل النهائي التشغيل؛ ويُودَع الخطأ تحت state['_stepErrors'][stepId]
timeoutMs int? مهلة زمنية فعلية لجسم العقدة بالمللي ثانية؛ null = بلا مهلة
teamId String? الفريق المطلوب إرساله (عقد team.dispatch)؛ لا يجتمع مع agentId
dispatchMode String? وضع تنفيذ الفريق: allParallel أو manager
extras Map<String, dynamic> تهيئة حرة خاصة بالجسم (مثل iterableKey وtemplateId وأشجار الشروط)

الموصّلات المشتقة: spaceId (extras['spaceId'] — محادثة قائمة يُنجَز العمل فيها)، وcreatesConversation (extras['createConversation'])، وconversationTitle (extras['conversationTitle'])، وmodeName (extras['mode'] — chat / review / plan، تُقرأ على العقدة التي تفتح المساحة)، وrunWhen (extras['runWhen'] — تخطي العقدة حين لا يتحقق الشرط).