- الرئيسية
- Documentation
- الجلسات
- تبديل الجلسة وعرض الجلسات الأخيرة
تبديل الجلسة وعرض الجلسات الأخيرة
يصف هذا المستند كيفية اكتشاف وكيل البرمجة للجلسات الأخيرة، وتحليل أهداف --resume، وعرض أدوات اختيار الجلسة، وتبديل جلسة التشغيل النشطة.
يركز على سلوك التنفيذ الحالي، بما في ذلك مسارات الاحتياط والتحفظات.
ملفات التنفيذ
Section titled “ملفات التنفيذ”../src/session/session-manager.ts../src/session/agent-session.ts../src/cli/session-picker.ts../src/modes/components/session-selector.ts../src/modes/controllers/selector-controller.ts../src/main.ts../src/sdk.ts../src/modes/interactive-mode.ts../src/modes/utils/ui-helpers.ts
اكتشاف الجلسات الأخيرة
Section titled “اكتشاف الجلسات الأخيرة”نطاق الدليل
Section titled “نطاق الدليل”يخزّن SessionManager الجلسات ضمن دليل مُحدَّد بنطاق cwd افتراضيًا:
~/.xcsh/agent/sessions/--<cwd-encoded>--/*.jsonl
تقرأ SessionManager.list(cwd, sessionDir?) ذلك الدليل فقط ما لم يُقدَّم sessionDir صريح.
مساران للعرض بحمولات مختلفة
Section titled “مساران للعرض بحمولات مختلفة”ثمة مساران مختلفان لمعالجة القوائم:
-
getRecentSessions(sessionDir, limit)(عرض الترحيب/الملخص)- يقرأ بادئة 4KB فقط (
readTextPrefix(..., 4096)) من كل ملف. - يحلل الترويسة ومعاينة أول نص مستخدم.
- يُعيد
RecentSessionInfoخفيف الوزن مع أدوات جلبnameوtimeAgoكسولة. - يرتب بترتيب تنازلي حسب
mtimeللملف.
- يقرأ بادئة 4KB فقط (
-
SessionManager.list(...)/SessionManager.listAll()(أدوات الاستئناف واستيفاء المعرّف)- يقرأ ملفات الجلسة الكاملة.
- يبني كائنات
SessionInfo(id،cwd،title،messageCount،firstMessage،allMessagesText، الطوابع الزمنية). - يُسقط الجلسات ذات صفر من إدخالات
message. - يرتب بترتيب تنازلي حسب
modified.
سلوك الاحتياط للبيانات الوصفية
Section titled “سلوك الاحتياط للبيانات الوصفية”للملخصات الأخيرة (RecentSessionInfo):
- تفضيل اسم العرض:
header.title-> أول موجه مستخدم ->header.id-> اسم الملف - يُقطع الاسم إلى 40 حرفًا للعروض المدمجة
- تُزال أحرف التحكم/أسطر السطر الجديد وتُصحح من الأسماء المستمدة من العنوان
لإدخالات قائمة SessionInfo:
titleهوheader.titleأو آخرshortSummaryللضغطfirstMessageهو نص أول رسالة مستخدم أو"(no messages)"
تحليل --continue وتفضيل بصمة الطرفية
Section titled “تحليل --continue وتفضيل بصمة الطرفية”تحلّ SessionManager.continueRecent(cwd, sessionDir?) الهدف بهذا الترتيب:
- قراءة بصمة نطاق الطرفية (
~/.xcsh/agent/terminal-sessions/<terminal-id>) - التحقق من صحة البصمة:
- يمكن تحديد الطرفية الحالية
- يتطابق cwd البصمة مع cwd الحالية (مقارنة المسار المحلول)
- الملف المُشار إليه لا يزال موجودًا
- إذا كانت البصمة غير صالحة/مفقودة، الاحتياط إلى أحدث ملف بـ mtime في دليل الجلسة (
findMostRecentSession) - إذا لم يُوجد أي ملف، إنشاء جلسة جديدة
يُفضّل اشتقاق معرّف الطرفية مسار TTY ويحتاط إلى معرّفات قائمة على البيئة (KITTY_WINDOW_ID، TMUX_PANE، TERM_SESSION_ID، WT_SESSION).
كتابات البصمة تبذل أفضل جهد ولا تُسبب فشلًا مميتًا.
تحليل هدف الاستئناف عند بدء التشغيل (main.ts)
Section titled “تحليل هدف الاستئناف عند بدء التشغيل (main.ts)”--resume <value>
Section titled “--resume <value>”تتعامل createSessionManager(...) مع --resume ذي قيمة نصية في وضعين:
-
قيمة شبيهة بالمسار (تحتوي على
/، أو\\، أو تنتهي بـ.jsonl)SessionManager.open(sessionArg, parsed.sessionDir)مباشرةً
-
قيمة بادئة المعرّف
- البحث عن تطابق في
SessionManager.list(cwd, sessionDir)عبرid.startsWith(sessionArg) - إذا لم يكن هناك تطابق محلي ولم يُفرض
sessionDir، جرّبSessionManager.listAll() - يُستخدم أول تطابق (لا يوجد موجه للغموض)
- البحث عن تطابق في
سلوك التطابق عبر المشاريع:
- إذا اختلف cwd الجلسة المُطابقة عن cwd الحالية، يسأل CLI إذا كان المستخدم يريد التفريع إلى المشروع الحالي
- نعم ->
SessionManager.forkFrom(...) - لا -> يُطلق خطأ (
Session "..." is in another project (...))
لا تطابق -> يُطلق خطأ (Session "..." not found.).
--resume (بدون قيمة)
Section titled “--resume (بدون قيمة)”يُعالج بعد إنشاء مدير الجلسة الأولي:
- عرض الجلسات المحلية باستخدام
SessionManager.list(cwd, parsed.sessionDir) - إذا كانت فارغة: طباعة
No sessions foundوالخروج مبكرًا - فتح أداة الاختيار TUI (
selectSession) - إذا أُلغي: طباعة
No session selectedوالخروج مبكرًا - إذا اختير:
SessionManager.open(selectedPath)
--continue
Section titled “--continue”يستخدم SessionManager.continueRecent(...) مباشرةً (السلوك المعتمد على البصمة أعلاه).
آليات الاختيار القائمة على أداة الاختيار
Section titled “آليات الاختيار القائمة على أداة الاختيار”أداة اختيار CLI (src/cli/session-picker.ts)
Section titled “أداة اختيار CLI (src/cli/session-picker.ts)”تُنشئ selectSession(sessions) واجهة TUI مستقلة مع SessionSelectorComponent وتحل مرة واحدة بالضبط:
- الاختيار -> يحل المسار المختار
- الإلغاء (Esc) -> يحل
null - الخروج القسري (مسار Ctrl+C) -> يوقف TUI ويستدعي
process.exit(0)
أداة الاختيار التفاعلية داخل الجلسة (SelectorController.showSessionSelector)
Section titled “أداة الاختيار التفاعلية داخل الجلسة (SelectorController.showSessionSelector)”التدفق:
- جلب الجلسات من دليل الجلسة الحالي عبر
SessionManager.list(currentCwd, currentSessionDir) - تركيب
SessionSelectorComponentفي منطقة المحرر باستخدامshowSelector(...) - ردود النداء:
- الاختيار -> إغلاق أداة الاختيار واستدعاء
handleResumeSession(sessionPath) - الإلغاء -> استعادة المحرر وإعادة العرض
- الخروج ->
ctx.shutdown()
- الاختيار -> إغلاق أداة الاختيار واستدعاء
سلوك مكوّن اختيار الجلسة
Section titled “سلوك مكوّن اختيار الجلسة”تدعم SessionList:
- التنقل بالأسهم/الصفحات
- Enter للاختيار
- Esc للإلغاء
- Ctrl+C للخروج
- البحث الضبابي عبر معرّف الجلسة/العنوان/cwd/أول رسالة/جميع الرسائل/المسار
سلوك عرض القائمة الفارغة:
- يعرض رسالة بدلًا من الانهيار
- Enter على القائمة الفارغة لا يفعل شيئًا (لا رد نداء)
- Esc/Ctrl+C لا يزالان يعملان
تحفظ: نص واجهة المستخدم يقول Press Tab to view all، لكن هذا المكوّن لا يحتوي حاليًا على معالج Tab والتوصيل الحالي يسرد جلسات النطاق الحالي فحسب.
تنفيذ التبديل في وقت التشغيل (AgentSession.switchSession)
Section titled “تنفيذ التبديل في وقت التشغيل (AgentSession.switchSession)”switchSession(sessionPath) هو مسار التبديل الأساسي داخل العملية.
دورة الحياة/انتقال الحالة:
- التقاط
previousSessionFile - إطلاق حدث هوك
session_before_switch(reason: "resume"، قابل للإلغاء) - إذا أُلغي -> إعادة
falseبدون تبديل - قطع الاتصال عن تدفق أحداث الوكيل الحالي
- إلغاء تدفق التوليد/الأداة النشط
- مسح المخازن المؤقتة لرسائل التوجيه/المتابعة/الدور التالي المُنتظرة
- مسح كاتب الجلسة (
sessionManager.flush()) لإبقاء الكتابات المعلقة sessionManager.setSessionFile(sessionPath)- يحدث مؤشر ملف الجلسة
- يكتب بصمة الطرفية
- يُحمّل الإدخالات / يُهاجر / يحل الكتلة / يُعيد الفهرسة
- إذا كانت بيانات الملف مفقودة/غير صالحة: يُهيئ جلسة جديدة في ذلك المسار ويُعيد كتابة الترويسة
- تحديث
agent.sessionId - إعادة بناء السياق عبر
buildSessionContext() - إطلاق حدث هوك
session_switch(reason: "resume"،previousSessionFile) - استبدال رسائل الوكيل بالسياق المُعاد بناؤه
- استعادة النموذج الافتراضي من
sessionContext.models.defaultإذا كان متاحًا وموجودًا في سجل النماذج - استعادة مستوى التفكير:
- إذا كان الفرع يحتوي بالفعل على
thinking_level_change، تطبيق مستوى الجلسة المحفوظ - وإلا اشتقاق مستوى التفكير الافتراضي من الإعدادات، تقليصه لقدرة النموذج، تعيينه، وإضافة إدخال
thinking_level_changeجديد
- إذا كان الفرع يحتوي بالفعل على
- إعادة توصيل مستمعي الوكيل وإعادة
true
إعادة بناء حالة واجهة المستخدم بعد التبديل التفاعلي
Section titled “إعادة بناء حالة واجهة المستخدم بعد التبديل التفاعلي”تُجري SelectorController.handleResumeSession إعادة تعيين واجهة المستخدم حول switchSession:
- إيقاف رسوم التحميل المتحركة
- مسح حاوية الحالة
- مسح واجهة الرسائل المعلقة وخريطة الأدوات المعلقة
- إعادة تعيين مراجع مكوّن/رسالة البث
- استدعاء
session.switchSession(...) - مسح حاوية الدردشة وإعادة العرض من سياق الجلسة (
renderInitialMessages) - إعادة تحميل المهام من مخرجات الجلسة الجديدة
- عرض
Resumed session
وهكذا يُعاد بناء حالة المحادثة/المهام المرئية من ملف الجلسة الجديد.
الاستئناف عند بدء التشغيل مقابل التبديل داخل الجلسة
Section titled “الاستئناف عند بدء التشغيل مقابل التبديل داخل الجلسة”الاستئناف عند بدء التشغيل (--continue، --resume، الفتح المباشر)
Section titled “الاستئناف عند بدء التشغيل (--continue، --resume، الفتح المباشر)”- يُختار ملف الجلسة قبل
createAgentSession(...). - تبني
sdk.tsالكائنexistingSession = sessionManager.buildSessionContext(). - تُستعاد رسائل الوكيل مرة واحدة أثناء إنشاء الجلسة.
- يُختار النموذج/التفكير أثناء الإنشاء (بما في ذلك منطق الاستعادة/الاحتياط).
- ثم يُشغّل الوضع التفاعلي
#restoreModeFromSession()لإعادة الدخول إلى حالة الوضع المستمرة (plan/plan_paused حاليًا).
التبديل داخل الجلسة (مسار أداة اختيار /resume)
Section titled “التبديل داخل الجلسة (مسار أداة اختيار /resume)”- يستخدم
AgentSession.switchSession(...)علىAgentSessionقيد التشغيل بالفعل. - تُعاد بناء الرسائل/النموذج/التفكير فورًا في مكانها.
- تُطلق أحداث هوك
session_before_switch/session_switch. - تُحدَّث دردشة واجهة المستخدم/المهام.
- لا يُجرى استدعاء مخصص لاستعادة الوضع بعد التبديل في تدفق أداة الاختيار؛ سلوك إعادة الدخول إلى الوضع ليس متماثلًا مع
#restoreModeFromSession()عند بدء التشغيل.
سلوك الفشل وحالات الحافة
Section titled “سلوك الفشل وحالات الحافة”مسارات الإلغاء
Section titled “مسارات الإلغاء”- إلغاء أداة اختيار CLI -> يُعيد
null، يطبع المُستدعيNo session selected، تخرج العملية مبكرًا. - إلغاء أداة الاختيار التفاعلية -> يُستعاد المحرر، لا تغيير في الجلسة.
- إلغاء الهوك (
session_before_switch) -> تُعيدswitchSession()القيمةfalse.
مسارات القائمة الفارغة
Section titled “مسارات القائمة الفارغة”- CLI
--resume(بدون قيمة): تطبع القائمة الفارغةNo sessions foundوتخرج. - أداة الاختيار التفاعلية: تعرض القائمة الفارغة رسالة وتبقى قابلة للإلغاء.
ملف الجلسة الهدف مفقود/غير صالح
Section titled “ملف الجلسة الهدف مفقود/غير صالح”عند الفتح/التبديل إلى مسار محدد (setSessionFile):
- ENOENT -> يُعامل كفارغ -> تُهيأ جلسة جديدة في ذلك المسار بالضبط وتُستمر.
- ترويسة مشوهة/غير صالحة (أو إدخالات محللة غير قابلة للقراءة فعليًا) -> تُعامل كفارغة -> تُهيأ جلسة جديدة وتُستمر.
هذا سلوك استرداد، لا فشل صارم.
الفشل الصارم
Section titled “الفشل الصارم”يمكن أن يُطلق التبديل/الفتح استثناءات عند أخطاء I/O الحقيقية (أخطاء الأذونات، أخطاء إعادة الكتابة، إلخ)، والتي تنتشر إلى المُستدعين.
تحفظات استيفاء بادئة المعرّف
Section titled “تحفظات استيفاء بادئة المعرّف”- يستخدم استيفاء المعرّف
startsWithويأخذ أول تطابق في القائمة المرتبة. - لا توجد واجهة للغموض إذا شاركت جلسات متعددة نفس البادئة.
- تستبعد
SessionManager.list(...)الجلسات ذات الصفر من الرسائل، لذا لا يمكن استئناف تلك الجلسات عبر استيفاء المعرّف/أداة اختيار القائمة.