أحداث النطاق
ناقل الأحداث
قسم بعنوان “ناقل الأحداث”DomainEventBus ناقل بث داخل العملية، بنمط النشر والاشتراك. يستدعي الناشرون publish(event)، ويستهلك المشتركون مجرى on<T>() مُنمَّطًا. كل حدث ينفّذ DomainEvent ويحمل occurredAt.
الناقل يعمل داخل cc_server. كل ناشر وكل مشترك حي يعيش هناك. لا يرى أي عميل هذا الناقل. يعيد الخادم توجيه مجموعة منتقاة كإطارات JSON-RPC من النمط notifications/*، مصفّاة لكل مشترك وفق عضوية مساحة العمل.
| المقياس | العدد |
|---|---|
| أصناف الأحداث الملموسة | 54 |
ملفات المصدر (packages/cc_domain/lib/core/domain/events/) |
14 (إضافة إلى domain_event_bus.dart) |
| القواعد المجرّدة التي لا تُنشَر مباشرة | 1 (TaskLifecycleEvent، تسلسل هرمي مختوم) |
كل حدث في الفهرس أدناه يعيش في ذلك الدليل الواحد، ولا تُعلَن أحداث نطاق في غيره.
أحداث مساحة العمل والوكيل والمستودع
قسم بعنوان “أحداث مساحة العمل والوكيل والمستودع”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
WorkspaceCreated |
workspaceId |
تُنشأ مساحة العمل |
AgentRunCompleted |
agentId، runId?، workspaceId?، conversationId? |
ينهي الوكيل تشغيلًا (نجاحًا أو فشلًا) |
AgentAwaitingInput |
workspaceId، kind، summary، spaceId?، conversationId?، agentId?، agentName? |
يبدأ وكيل انتظار إنسان: موافقة، أو سؤال ask_user، أو تشغيل متوقّف بسبب بيانات اعتماد (قيمة kind هي approval أو question أو credential) |
RepoAdded |
repoId، path، workspaceId |
يُسجَّل مستودع، ويُطلَق فهرسة الشفرة في الخلفية |
SkillUpdated |
workspaceId، slug، origin، computedHash، scanVerdict? |
تُثبَّت مهارة أو تُحدَّث، حاملة حكم فحص سلسلة التوريد |
أحداث طلبات السحب والمراجعة
قسم بعنوان “أحداث طلبات السحب والمراجعة”الكتلة الأولى هي دورة حياة طلب السحب نفسه. والثانية هي مراقبة طلب السحب المؤلَّف: إشارات عن طلب سحب فتحته أنت، وكل منها يحمل forUserId حتى يستطيع الاستطلاع توجيهها إلى الشخص المعني بدل بثّها.
| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
PullRequestPublished |
prId، workspaceId، repoOwner، repoName |
يفتح الوكيل طلب سحب |
PullRequestStatusChanged |
status، workspaceId، prId?، repoFullName?، prNumber? |
يُدمَج طلب السحب أو يُغلَق أو يُفتَح أو يُعاد فتحه أو يُوافَق عليه |
PrMerged |
prId، workspaceId، agentId |
يُدمَج طلب السحب. إشارة ضيقة خاصة بالدمج، تُحفَظ للتحليلات والإشعارات |
PrReviewRequested |
workspaceId، repoOwner، repoName، prNumber، prTitle |
يطلب GitHub مراجعة مستخدم الخادم (استطلاع الإشعارات، review_requested) |
PrMentioned |
workspaceId، repoOwner، repoName، prNumber، prTitle |
يُشار إلى مستخدم الخادم في طلب سحب (استطلاع الإشعارات، mention) |
ExternalPrMerged |
workspaceId، repoOwner، repoName، prNumber، prTitle، mergedByLogin? |
دُمج طلب سحب متتبَّع خارجيًا (ليس من وكيل)، اكتشفه استطلاع إشعارات GitHub، ويُقابَل بفئة الإشعار prMerged |
ExternalPrDetected |
repoOwner، repoName، prNumber، prTitle، author، workspaceId? |
وُجد طلب سحب ليس من وكيل عبر الاستطلاع. لخط الأنابيب فقط (يدفع external_pr_welcome)، ولا يرفع إشعارًا |
PrHeadChanged |
repoOwner، repoName، prNumber، prTitle، previousHeadSha، headSha، workspaceId |
تحرّك SHA رأس طلب السحب. دفع المؤلف |
ReviewBecameStale |
workspaceId، spaceId، repoOwner، repoName، prNumber، prTitle، reviewedHeadSha، headSha |
لم تعد مراجعة ذكاء اصطناعي منتهية تصف طلب السحب الذي راجعته. لا يُطلَق إلا حين توجد مراجعة للإيداع المستبدَل، فيبقى إشارة لا تنبيهًا عند كل دفع |
مراقبة طلب السحب المؤلَّف
قسم بعنوان “مراقبة طلب السحب المؤلَّف”تحمل الستة كلها workspaceId وrepoOwner وrepoName وprNumber وprTitle وforUserId اختياريًا.
| الحدث | حمولة إضافية | متى يُطلَق |
|---|---|---|
PrMergeReadinessChanged |
ready، reason |
صار طلب سحب ألّفته قابلًا للدمج، أو كفّ عن ذلك |
PrReviewDecisionChanged |
decision، reviewersRemaining، approverLogin? |
وافق مراجع، أو طلب تغييرات، أو أُسقطت موافقة |
PrChecksStatusChanged |
failing، failingCheckName?، failingCheckUrl? |
احمرّ CI، أو تعافى |
PrCommentMentioned |
commentId، authorLogin، bodyPreview، isReviewComment، threadId?، path?، line? |
أشار إليك أحد في تعليق على طلب السحب أو في تعليق مراجعة |
PrThreadReplied |
commentId، authorLogin، bodyPreview، threadId?، path?، line? |
رد أحد في خيط مراجعة أنت فيه |
PrThreadResolved |
threadId، commentId?، path?، line? |
حلّ أحد خيط مراجعة أنت فيه |
أحداث المراسلة
قسم بعنوان “أحداث المراسلة”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
MessageReceived |
spaceId، messageId، senderName، contentPreview، isAgentMessage، workspaceId?، mentions، requestedByUserId?، senderUserId? |
تصل رسالة جديدة |
SpaceCreated |
spaceId، workspaceId |
تُنشأ مساحة |
SpaceDeleted |
spaceId، workspaceId |
تُحذف مساحة |
SpaceProvisioningChanged |
workspaceId، spaceId، status، step? |
تدخل مساحة العمل التابعة للمساحة في التجهيز، أو تبلغ خطوة (استنساخ مستودع، أو إخراج طلب سحب، أو إعداد وكيل)، أو تنقلب إلى جاهز أو فاشل. يروي جسر الدردشة ذلك على بطاقة مهمته |
أحداث التذاكر
قسم بعنوان “أحداث التذاكر”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
TicketCreated |
ticketId، workspaceId |
تُنشأ تذكرة |
TicketAssigned |
ticketId، ticketTitle، ticketBody?، ticketUrl?، assignedAgentId?، assigneeType، assignedTeamId?، workspaceId |
تُسنَد التذكرة إلى Principal أو إلى فريق |
TicketCompleted |
ticketId |
ينتهي العمل (نهائي) |
TicketFailed |
ticketId، errorMessage |
يفشل الوكيل (نهائي) |
TicketCancelled |
ticketId |
تُلغى التذكرة (نهائي) |
TicketStatusChanged |
ticketId، workspaceId، from، to |
أي تغيّر في الحالة |
TicketReassigned |
ticketId، workspaceId، fromAgentId?، toAgentId? |
تُعاد إسناد التذكرة |
TicketDetailsUpdated |
ticketId، workspaceId |
يتغيّر العنوان أو الوصف أو الأولوية |
أحداث دورة حياة المهمة
قسم بعنوان “أحداث دورة حياة المهمة”مجرى دورة حياة المهمة الموحّد: تشغيل وكيل مُرسَل واحد، مفتاحه معرّف سجل التشغيل. يحمل كل حدث taskId، وseq رتيبًا لكل مهمة، وworkspaceId?، وagentId?، وphase، ولا تسرد الصفوف أدناه إلا الحقول الإضافية.
| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
TaskDispatched |
— | تُسلَّم المهمة إلى خلفية للتنفيذ |
TaskRunning |
— | بدأت المهمة إنتاج مخرج |
TaskWaitingLocalDirectory |
lockedPath، holderTaskId? |
تُوقَف المهمة. تملك مهمة أخرى قفل المسار على القرص الذي تحتاجه |
TaskProgress |
note? |
نقطة تفتيش لتقدّم في منتصف التشغيل |
TaskMessage |
messageType، content |
رسالة متدفقة (text/thinking/tool_use/tool_result/error)، وتُبلَّغ تحت طور progress |
TaskCompleted |
summary? |
انتهت المهمة بنجاح |
TaskFailed |
errorMessage |
انتهت المهمة بخطأ |
TaskCancelled |
— | أُلغيت المهمة قبل الاكتمال |
يحمل تعداد TaskPhase أيضًا عضو queued، لكن لا شيء ينشر حدث انتظار، فلا يوجد صنف TaskQueued. أول إطار يمكن ملاحظته لمهمة هو TaskDispatched.
أحداث خط الأنابيب
قسم بعنوان “أحداث خط الأنابيب”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
PipelineRunCompleted |
workspaceId، pipelineRunId، templateId |
ينتهي التشغيل |
PipelineRunCancelled |
workspaceId، pipelineRunId، templateId |
يُلغى التشغيل (من المستخدم أو من النظام). توقّف متعمّد، لا خطأ |
PipelineRunFailed |
workspaceId، pipelineRunId، templateId، errorMessage |
يفشل التشغيل |
لا تُنشَر إلا الانتقالات النهائية. لا يوجد PipelineRunStarted ولا حدث لكل خطوة: يصل تقدّم الخطوة إلى العملاء عبر صفوف التشغيل نفسه ومجرى دورة حياة المهمة للوكيل الذي أرسلته، لا عبر الناقل.
أحداث الرصد
قسم بعنوان “أحداث الرصد”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
ActivityLogged |
id، actorType، actorId?، action، entityType، entityId?، details?، workspaceId?، runId? |
يُنشأ بند في سجل النشاط |
BudgetThresholdCrossed |
scopeType، scopeId، spentCents، budgetCents، isHardStop |
يتجاوز الإنفاق العتبة |
أحداث الهوية والعضوية
قسم بعنوان “أحداث الهوية والعضوية”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
WorkspaceMemberAdded |
workspaceId، userId، role |
ينضم مستخدم إلى مساحة عمل (استرداد دعوة أو إضافة من مسؤول) |
WorkspaceMemberRemoved |
workspaceId، userId |
يُزال عضو. يجب أن تعيد الجلسات الحيّة لذلك المستخدم، المحصورة في مساحة العمل، التحقق من الوصول فورًا |
WorkspaceMemberRoleChanged |
workspaceId، userId، role |
يتغيّر دور عضو |
العضوية هي سطح الهوية كله على الناقل. يحدث إنشاء المستخدم وإلغاء الجهاز، لكنهما لا يُنشران كأحداث نطاق. يُفرَض الإلغاء مباشرة على الجلسات الحيّة بدل توجيهه عبر الناقل.
أحداث التقويم والاجتماعات
قسم بعنوان “أحداث التقويم والاجتماعات”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
CalendarAuthExpired |
workspaceId، accountEmail |
يصير رمز تحديث OAuth لحساب متصل غير صالح بشكل دائم (يُنشَر مرة واحدة لكل حادثة انقطاع) |
MeetingStartingSoon |
workspaceId، eventId، title، startTime، meetingUrl? |
يوشك حدث تقويم أن يبدأ ضمن نافذة الاستباق المُعدّة |
MeetingRecordingStopped |
workspaceId، meetingId، title، userNotes، transcript، summaryInstructions? |
ينتهي تسجيل اجتماع ويُطلِق خط الأنابيب المضمّن meeting_summary |
أحداث المنصات
قسم بعنوان “أحداث المنصات”| الحدث | الحمولة | متى يُطلَق |
|---|---|---|
RigClosedEvent |
workspaceId، rigId، reason |
زالت منصة، ومعها سبب إغلاقها. لا يتصرف المستهلكون إلا عند backendFailure. كل سبب آخر مطلوب أو مصحوب بـ RigReaped |
RigControlChanged |
workspaceId، rigId، controller? |
تولّى إنسان التحكم الحصري بمنصة أو أعادها (controller يساوي null عند التحرير. لا يسجّل الحدث من أفلت التحكم) |
RigReaped |
workspaceId، rigId، reason، agentId? |
استرد النظام آلة: خمول، أو TTL، أو طرد بسبب ضغط الذاكرة (يُبلَّغ كـ idleTimeout)، مع الوكيل الدافع |
فتح منصة ليس حدثًا. يكتمل الإقلاع وينقلب صف المنصة إلى جاهز، ولا يُنشَر شيء، فلا يوجد RigOpened للاشتراك فيه.
نطاقات فرعية بلا أحداث أصلًا
قسم بعنوان “نطاقات فرعية بلا أحداث أصلًا”عدة أنظمة فرعية تبدو من الخارج مدفوعة بالأحداث، وهي ليست كذلك. تُدرَج هنا لأن غيابها قرار تصميم يجدر معرفته قبل البحث عن خطاف:
| النطاق الفرعي | كيف تتحرك الحالة بدل ذلك |
|---|---|
| الذاكرة | record_memory_fact وأشباهها تكتب وتعيد، والاسترجاع يقرأ. لا يُنشَر شيء عند حقيقة أو تعارض |
| التنسيق | الاقتراح وموافقته وتشغيل خط الأنابيب المولَّد صفوف واستدعاءات RPC |
| مستندات الخطط | submit_plan يكتب إصدارًا، والموافقة تجسّد تنسيقًا. لا يُعلَن أي منهما |
| المخرجات | publish_artifact / revise_artifact يكتبان الإصدارات مباشرة |
| الموافقات | يُعالَج التصعيد داخل خدمة سير عمل الموافقة |
| مزامنة التذاكر | يشترك منسّق المزوّد في أحداث التذاكر أعلاه، وتُطبَّق ويب هوك الواردة مباشرة |
| تحديث التقويم | تُدرج المزامنة الأحداث أو تحدّثها، ويعيد العميل قراءتها، ولا يوجد بث للتحديث |
| دمج أشجار العمل | يُسجَّل في worktree_merge_log ويُقرأ من هناك |
المشتركون
قسم بعنوان “المشتركون”يُبنى كل مشترك أدناه داخل runCcServer (أو خدمة يبنيها). لا يوجد مشترك على جانب العميل.
| المشترك | الأحداث التي يستهلكها |
|---|---|
WorkspaceSeeder |
WorkspaceCreated |
| بذر حزمة التقييم الابتدائية (مضمّن) | WorkspaceCreated |
| تجهيز مساحة الدردشة (مضمّن) | SpaceCreated |
PipelineTriggerDispatcher |
كل DomainEvent، ويصفّي كل مشغّل مفعّل حسب نوعه |
SubPipelineResumeListener |
PipelineRunCompleted، PipelineRunFailed |
PipelineCostRollupListener |
AgentRunCompleted |
BudgetEvaluationListener |
AgentRunCompleted |
MeetingSummaryReconciler |
PipelineRunCompleted، PipelineRunFailed، PipelineRunCancelled (تشغيلات meeting_summary فقط) |
PipelineStepResumeListener |
AgentRunCompleted |
AgentRunTaskCompleter |
AgentRunCompleted |
GoalSupervisor |
AgentRunCompleted |
CheckerDispatchListener |
AgentRunCompleted |
TeamRoutingService |
AgentRunCompleted، TicketAssigned |
OrchestrationRunListener |
PipelineRunCancelled، PipelineRunFailed |
MultiVendorTicketSyncCoordinator |
TicketCreated، TicketAssigned، TicketReassigned، TicketStatusChanged، TicketDetailsUpdated |
WorktreeGcListener |
TicketCompleted، TicketCancelled، SpaceDeleted، PrMerged، PullRequestStatusChanged |
ChatBridgeService |
MessageReceived، SpaceProvisioningChanged |
ActivityLogPersister |
ActivityLogged |
RigEventListener |
RigControlChanged، RigReaped، RigClosedEvent. يحقن إشعارًا بلغة واضحة في مسار توجيه الوكيل الدافع |
StaleReviewWatcher |
PrHeadChanged. ينشر ReviewBecameStale فقط حين توجد مراجعة منتهية للإيداع المستبدَل |
GitHubPrConversationBridge |
AgentRunCompleted. ردود صادرة في محادثة طلب السحب |
NotificationFeedRecorder |
أحداث صنف الإشعارات الاثنان والعشرون أدناه |
RemoteEventForwarder |
تلك الاثنان والعشرون إضافة إلى TicketReassigned وكل TaskLifecycleEvent. أحداث العضوية الثلاثة تُبطل فقط ذاكرة عضويته المؤقتة لكل مساحة عمل، ولا تُمرَّر كإطارات |
LocalRpcServer / RemoteRelayHost |
WorkspaceMemberRemoved. يُسقط اشتراكات مساحات العمل المرتبطة بذلك المستخدم، ويبقى المقبس مفتوحًا |
TicketAssigned إشارة تدقيق وإشعار، ومشغّل لخط أنابيب. الإسناد إلى وكيل يسجّل الملكية ولا يبدأ تشغيلًا، فلا يوجد موزّع تذاكر. الإسناد إلى فريق (عند تعيين assignedTeamId) هو الاستثناء: يرسل TeamRoutingService قائد الفريق.
TicketRemoteSyncHandler مُعلَن، لكنه لا يُبنى في شفرة الإنتاج، فلا يشترك في شيء اليوم. لا يُبنى NotificationEventMapper على جانب العميل إلا في اختباره، وهو بقية المسار داخل العملية من قبل فصل العميل عن الخادم. الإشعارات المنبثقة الحيّة تأتي من إطارات السلك أدناه.
تعيين الإشعارات
قسم بعنوان “تعيين الإشعارات”على الخادم يحوّل NotificationFeedRecorder وRemoteEventForwarder هذه الأحداث إلى إطارات سلك من النمط notifications/* (notification_wire.dart). على العميل يحوّل RpcNotificationMapper ثم mapNotificationFrame الإطار إلى AppNotification.
هناك سبع عشرة فئة إشعار بالضبط. تُقابَل عدة أحداث بأكثر من أسلوب سلك، لأن الإطار يحمل الحافة (الفشل مقابل التعافي) بينما تحمل الفئة السؤال («ماذا يفعل CI؟»).
| الفئة | حدث المصدر | أسلوب السلك |
|---|---|---|
newMessage |
MessageReceived |
notifications/message_received (يشير إليك) |
agentRunCompleted |
MessageReceived |
notifications/message_received (is_agent_message، دون إشارة إليك) |
agentAwaitingInput |
AgentAwaitingInput |
notifications/agent_awaiting_input |
ticketAssigned |
TicketAssigned |
notifications/ticket_assigned |
ticketStatusChanged |
TicketStatusChanged |
notifications/ticket_status_changed |
pullRequestPublished |
PullRequestPublished |
notifications/pr_published |
prMerged |
PrMerged |
notifications/pr_merged |
prMerged |
ExternalPrMerged |
notifications/external_pr_merged |
prMentioned |
PrMentioned |
notifications/pr_mentioned |
prMentioned |
PrCommentMentioned |
notifications/pr_comment_mentioned |
reviewRequested |
PrReviewRequested |
notifications/pr_review_requested |
reviewStale |
ReviewBecameStale |
notifications/review_stale |
prMergeReadiness |
PrMergeReadinessChanged |
notifications/pr_ready_to_merge / pr_merge_blocked |
prReviewDecision |
PrReviewDecisionChanged |
notifications/pr_approved / pr_changes_requested / pr_review_dismissed |
prChecksStatus |
PrChecksStatusChanged |
notifications/pr_checks_failed / pr_checks_recovered |
prThreadActivity |
PrThreadReplied |
notifications/pr_thread_replied |
prThreadActivity |
PrThreadResolved |
notifications/pr_thread_resolved |
meetingStartsSoon |
MeetingStartingSoon |
notifications/meeting_starting_soon |
calendarAuthExpired |
CalendarAuthExpired |
notifications/calendar_auth_expired |
rigStatusChanged |
RigControlChanged |
notifications/rig_control_changed |
rigStatusChanged |
RigReaped |
notifications/rig_reaped |
rigStatusChanged |
RigClosedEvent |
notifications/rig_closed |
لا يُعاد إطار تولّي المنصة إلى من أخذ التحكم، ويُمرَّر التحرير بلا تصفية (لا يسجّل الحدث من أفلت التحكم)، ولا ينتج إطار rig_closed إلا إغلاق بسبب backendFailure. الأسباب الأخرى إما مطلوبة، أو يغطيها إطار الاسترداد أصلًا.
ينشر AgentAwaitingInputPublisher الحدث AgentAwaitingInput، فهو يراقب سجلَّي الموافقات وحظر بيانات الاعتماد بحثًا عن إدخالات جديدة، ويُبلغه AgentQuestionService بكل سؤال ask_user. الانتظار الواحد حدث واحد، ولا يُنشَر شيء عند انتهاء الانتظار.
تحمل فئات طلب السحب المؤلَّف الخمس forUserId، فتصل إلى المؤلف لا إلى كل من في مساحة العمل.
يُمرِّر RemoteEventForwarder أيضًا TicketReassigned بصورة notifications/ticket_reassigned، وكل TaskLifecycleEvent بصورة notifications/task_<phase>. لا يُقابَل أي منهما بفئة إشعار: يقودان الواجهة الحيّة، لا مركز الإشعارات. لا تُمرَّر أحداث العضوية كإطارات: تُبطل ذاكرة المُمرِّر المؤقتة، وتُسقط مضيفات الجلسة اشتراكات مساحة العمل الخاصة بالعضو المُزال.