كل الأعمال

XPath

أداة إصدار مستضافة ذاتياً لتطبيقات Flutter: ابنِ ووقّع وارفع ووسم وتتبّع من جهاز الماك الخاص بك.

الدور
بمفردي، من البداية إلى النهاية
الحالة
مُصدر، الإصدار 1.0
متى
2026
التقنيات
  • Dart
  • Flutter macOS
  • SQLite
  • WebSocket
  • MCP
  • Docker
  • Homebrew
روابط
xpath.abdurahman.lyالمصدر

محرك واحد بلا واجهة يملك المشاريع والأسرار والمهام وحالة المتاجر. يتحدث إليه تطبيق ماك وواجهة سطر أوامر وخادم MCP لوكلاء الذكاء الاصطناعي ومشغّلات عن بُعد، وهو يُصدر إلى App Store Connect وGoogle Play وFirebase App Distribution وShorebird.

سجل القرارات الكامل متاح بالإنجليزية.

Context

Releasing a Flutter app means Xcode, Gradle, two stores, signing material and often Shorebird, repeated for every app and every store account. Hosted CI does it, but it holds your signing keys and bills by the minute on a Mac you do not own. Local scripts are cheap until a release half fails at an upload and nobody knows which steps already ran.

Decisions

One engine, four clients. The engine, xpd, owns state and does the work; the Mac app, the xp command line, the MCP server and remote runners are all clients of the same HTTP and WebSocket API. Nothing is possible only from the GUI, so an agent and a person have the same reach, except that an agent can dispatch a release but never approve a gate.

The domain logic is a framework-free package that defines interfaces only. SQLite, git, GitHub, the stores, processes and the Keychain live in adapters, and a layer check in the repository fails the build if the core imports one. The end to end tests run against fake App Store Connect, Google Play and Firebase servers.

Cancel means the whole process tree. A build is flutter calling xcodebuild or gradle calling compilers, and killing the direct child leaves the rest running. Dart cannot run code between fork and exec, so every step starts through a one-line perl trampoline that makes it a process group leader, and cancel signals the group: SIGTERM, then SIGKILL ten seconds later.

Crash recovery is decided by side effects. After a restart, a job that was building or testing resumes on its own. A job that was uploading, tagging, pushing or merging waits for a person, because running a side effect twice is worse than a stalled job.

Runners are the least trusted machines. A runner token reaches the runner endpoints and nothing else, enforced by one middleware so a new route is closed to runners until someone opens it on purpose. Runners fetch source with their own SSH key; the GitHub token never leaves the engine.

Consequences

Version 1.0 shipped as a notarized Mac app through a Homebrew cask, with Linux bundles and a Docker image for the engine and runners. Thirteen architecture decision records sit in the repository, each written when the question came up rather than after.

The cost of self-hosting is that you are the operator: the build Mac, its disk and its Xcode versions are yours to keep healthy. XPath reports disk use and toolchain errors, but it cannot buy you a second Mac.