fix: expose project registration and align Linux app id

This commit is contained in:
Hamza Ayed
2026-10-04 02:20:09 +03:00
parent 5ab7ec2713
commit ddfb26c14f
5 changed files with 90 additions and 2 deletions
+5 -1
View File
@@ -8,6 +8,10 @@
- اختبار سقف التخزين: نجح `scripts/verify_vhd_disk_quota.ps1` بقرص VHDX مؤقت 64MiB؛ كتب 53,477,376 بايت حتى `ERROR_DISK_FULL` (112)، بقي 151,552 بايت حرًا، وحُذف قرص الاختبار بعد التحقق. سكربت القرص الدائم 1GiB اجتاز تحليل PowerShell بعد إصلاحه، لكن `Status` أكد عدم وجود القرص؛ محاولات UAC عبر Windows PowerShell وPowerShell 7 و`cmd.exe` انتهت بخطأ بدء `0xc0000142` قبل أي تعديل. لذلك لا يوجد حتى الآن VHDX دائم، ولا يُسمح للوكيل بتنفيذ أوامر.
- تهيئة Linux: وُحّد `APPLICATION_ID` مع اسم سطح المكتب والأيقونة إلى `com.mithqal.ai`، وأضيف دليل اعتماديات البناء والتشغيل الآمن مع Libsecret وخدمة Secret Service في `flutter_app/linux/packaging/README.md`. لم يُنفذ بناء أو اختبار Linux أصلي على هذا المضيف Windows؛ بند Linux/macOS لا يزال مفتوحًا حتى يتحقق البناء ومخزن الجلسة على المنصات نفسها.
- وضوح تسجيل المشروع في النافذة الضيقة: أضيف إجراء دائم في الشريط العلوي بعنوان وصولي «تسجيل مشروع من مجلد موجود»، لأن القائمة الجانبية تختفي عند عرض 760px أو أقل. يحتفظ بسلوك اختيار مجلد موجود وتسجيله. تحقق اختبار واجهة عند عرض 700px من ظهور الإجراء رغم اختفاء القائمة؛ مجموعة `widget_test.dart` نجحت 6/6 و`flutter analyze --no-pub` بلا ملاحظات (2026-10-04). لم يُستبدل التطبيق المفتوح ببناء جديد في هذه الخطوة.
- متابعة التقييم على ملفات المشروع الفعلية: أضيفت مرادفات `permission/permissions/صلاحية/صلاحيات` لرموز صلاحيات الأدوات، فأصبح المقطع العميق `tool_name not in selected_skill.allowed_tools` يظهر ضمن نتائج السؤال الذي كان يفشل سابقًا؛ تقييم الاسترجاع 9/9 أدلة (`evals/results/retrieval_project_permission_synonym_2026-10-03.json`). هذا يقيس العثور على المصدر لا جودة صياغة Gemma. أضيف حدّ سياق لأربع مقاطع وإزالة التكرار وتوزيع المقاطع على ملفات مختلفة. في 2026-10-03 أُعيد تشغيل FastAPI من الشفرة الحالية بعد اكتشاف أن الخدمة الحية كانت أقدم من تعديل السياق. على الخدمة الجديدة، أعاد التقييم الكامل 11/11 ملفًا مستهدفًا في المرتبة الأولى ووجد الدليل 11/11 (`evals/results/retrieval_project_agent_fresh_api_2026-10-03.json`). مراجعة يدوية أولية لإجابات الجولة وجدت 9/11 إجابات مباشرة؛ سؤال ترحيل الإجابات وسؤال توجيه الصور امتنعا رغم وجود الدليل، لكن إعادة كل حالة منفردة أجابت عنها مع اقتباس المصدر (`evals/results/retrieval_project_agent_migration_retry_2026-10-03.json` و`evals/results/retrieval_project_agent_routing_retry_2026-10-03.json`). هذا يكشف تذبذب جودة التوليد، ولا يعادل درجات مستقلة؛ مراجعة بشرية أوسع ما زالت مفتوحة. اختبارات Flutter الكاملة الآن 16/16، واختبارات Python الكاملة عبر `unittest` الآن 89/89 (2026-10-03). فحص `compileall` و`git diff --check` ناجحان.
- تحقق تشغيل حديث: أُعيد تشغيل FastAPI على `127.0.0.1:8000` من نسخة المشروع الحالية مع Ollama وGemma 4؛ `/health` أعاد `ok`، والجلسة المحلية أكدت وضع الوكيل متعدد الخطوات وحده 3، وتجربة API حية اختارت `calculator` وأعادت `391.0` لـ17×23. في 2026-10-03 اختُبر أيضًا طلب بحث+حساب حي: `search_workspace` أعاد `MAX_AGENT_TOOL_CALLS = 3` من `app/main.py`، ثم الحاسبة أعادت `21` لـ3×7 في خطوتين. بقي تطبيق Windows Debug شغّالًا، وظل ملف SQLite المحلي موجودًا في مساره. اختبارات Python الكاملة 83/83؛ اختبارات Flutter 15/15 و`flutter analyze` بلا ملاحظات من الجولة السابقة، ولم تتغير واجهة Flutter في هذه الخطوة.
@@ -91,7 +95,7 @@
- [x] HTTPS محلي اختياري لعميل Windows/Dart والمتصفح: أضيف `scripts/setup_local_tls.ps1` لإنشاء جذر تطوير خاص بـ`CurrentUser\Root` وشهادة خادم SAN لـ`localhost` و`127.0.0.1`؛ يقيّد ACL لمفتاح الخادم للمستخدم و`SYSTEM` ويحذف مفتاح الجذر بعد التوقيع. أضيف `start-api-https.ps1` لمنفذ 8443 و`remove_local_tls.ps1` لإزالة الشهادات والملفات المحددة. في 2026-10-04 أعاد Windows PowerShell وDart `HttpClient` الحالة 200 عبر الاسمين؛ فتح Edge headless صفحة `/health` وأظهر JSON بالحالة 200. رفض HTTPX بمخزن CA الافتراضي الشهادة الخاصة. أُوقف خادم الاختبار وبقي HTTP 8000 كما هو. `curl.exe` احتاج `--ssl-no-revoke` بسبب غياب CRL لجذر التطوير؛ لا نعطل فحص الشهادات في التطبيق. الإعداد loopback للتطوير فقط وليس شهادة عامة أو وصولًا شبكيًا.
- [x] حد أولي دائم لتخمين كلمات المرور وإنشاء الحسابات في SQLite مع نافذة انتهاء و`Retry-After`؛ اختبرته مجموعة Python كاملة، وتبقى مراجعة الحدود تحت reverse proxy موثوق قبل أي نشر خارجي.
- [x] تعطيل حفظ رمز الجلسة الدائم في الويب؛ استخدام مخزن ذاكرة مؤقت وإظهار ذلك للمستخدم.
- [ ] التحقق من متطلبات Linux keyring وتشغيل تخزين الجلسة الأصلي، وبناء macOS وLinux على منصات فعلية.
- [ ] التحقق من متطلبات Linux keyring وتشغيل تخزين الجلسة الأصلي، وبناء macOS وLinux على منصات فعلية. متطلبات Linux المبدئية موثقة في `flutter_app/linux/packaging/README.md` ومعرّف GTK يطابق `com.mithqal.ai`؛ الاختبار الأصلي على Linux لم يُنفذ، واختبار Keychain والبناء على macOS ما زالا مطلوبين.
- [x] تثبيت مكوّن C++ ATL في Visual Studio Build Tools؛ تحقق وجود `atlstr.h` ونجح `flutter build windows --debug` (2026-10-03).
- تصميم بيانات المستخدمين والمحادثات والمرفقات ونسخ الإجابات مع ملكية واضحة وفهارس وترحيلات قاعدة بيانات.
- SQLite مناسب لنسخة محلية أحادية الجهاز. عند تشغيل خدمة لعدة مستخدمين/أجهزة، ننتقل إلى PostgreSQL، مع نسخ احتياطية وسياسة حذف وتصدير.
@@ -1407,6 +1407,11 @@ class _ChatPageState extends State<ChatPage> {
),
),
SizedBox(width: compact ? 2 : 12),
IconButton.filledTonal(
onPressed: chat.isSending ? null : _addWorkspaceProject,
tooltip: 'تسجيل مشروع من مجلد موجود',
icon: const Icon(Icons.create_new_folder_outlined),
),
IconButton(
onPressed: _chooseWorkspace,
tooltip:
@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
set(BINARY_NAME "flutter_app")
# The unique GTK application identifier for this application. See:
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
set(APPLICATION_ID "com.example.flutter_app")
set(APPLICATION_ID "com.mithqal.ai")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
@@ -0,0 +1,46 @@
# Linux desktop build and runtime
The Linux desktop entry, installed icon, and GTK application must all use the
same application ID: `com.mithqal.ai`.
## Ubuntu and Debian build dependencies
Install Flutter's Linux desktop toolchain and the native secret-storage
development library:
```sh
sudo apt-get update
sudo apt-get install -y \
clang cmake ninja-build pkg-config libgtk-3-dev libstdc++-12-dev \
libsecret-1-dev libsecret-1-0
```
Then check the host and build the release bundle:
```sh
flutter doctor -v
flutter devices
flutter pub get
flutter build linux --release
```
The executable bundle is produced at
`build/linux/x64/release/bundle/`. Distribute the complete bundle and verify
its native runtime dependencies on the target distribution, for example with
`ldd build/linux/x64/release/bundle/flutter_app`.
## Secure session storage
`flutter_secure_storage` uses Libsecret on Linux. Build machines need
`libsecret-1-dev`; packaged applications need the runtime library
`libsecret-1-0`. The desktop session must also provide D-Bus and an unlocked
Secret Service keyring, commonly GNOME Keyring or KDE Wallet. Run the
application in an interactive desktop session to verify login, token
persistence after restart, and logout deletion. Do not treat a successful
Linux build as proof that secure storage works: headless sessions and CI may
have no unlocked keyring.
Upstream setup references:
- [Flutter Linux development setup](https://docs.flutter.dev/platform-integration/linux/setup)
- [flutter_secure_storage Linux implementation](https://pub.dev/documentation/flutter_secure_storage_linux/latest/)
@@ -182,6 +182,39 @@ void main() {
await chatCubit.close();
});
testWidgets('project registration stays visible when sidebar is hidden', (
tester,
) async {
tester.view.physicalSize = const Size(700, 600);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.resetPhysicalSize);
addTearDown(tester.view.resetDevicePixelRatio);
final api = _TestApiRepository();
final chatCubit = ChatCubit(
api,
settingsStore: LocalSettingsStore.inMemory(),
);
await tester.pumpWidget(
MultiRepositoryProvider(
providers: [RepositoryProvider<ApiRepository>.value(value: api)],
child: MultiBlocProvider(
providers: [
BlocProvider.value(value: chatCubit),
BlocProvider(create: (_) => VoiceCubit(api, AudioRecorder())),
],
child: const SovereignApp(),
),
),
);
await tester.pumpAndSettle();
expect(find.text('مشاريعي'), findsNothing);
expect(find.byTooltip('تسجيل مشروع من مجلد موجود'), findsOneWidget);
expect(tester.takeException(), isNull);
await chatCubit.close();
});
testWidgets('model selector displays capabilities reported by Ollama', (
tester,
) async {