الأكاديمية ← دليل المطوّرتوثيق رسمي · إرشاد عربي

تطوير الواجهات من Worktrees

TUI & Desktop from Worktrees

متقدم5 دقائق قراءةالدرس 104 أسئلة✓ 2026-08-18
قبل أن تقرأ

ما هذه الصفحة، وماذا تحتوي.

التثبيت: تنزيل Hermes وتجهيزه على جهازك، مع كل ما يحتاجه ليعمل. معظم المشاكل التي تبدو معقّدة لاحقًا سببها خطوة ناقصة هنا. الصفحة فيها تحذير من المصدر، و5 دقائق قراءة. انتبه: اقرأ ما سيفعله المثبّت قبل تشغيله، وشغّل hermes doctor بعده ليخبرك بما ينقص.

5أقسام
4أمثلة برمجية
2جداول
0أوامر
927كلمة من المصدر
الوصف الرسمي في سطر

Run the Ink TUI and Electron desktop app from a git worktree without a full npm install per checkout

ماذا ستستطيع بعدها

نتائج مأخوذة من هذه الصفحة، لا من قالب.

  • تعرف ما التثبيت ولماذا قد تحتاجه.
  • تقرأ الجدول وتأخذ منه السطر الذي يخصّك فقط.
  • تضبط HERMES_MAIN_CHECKOUT في المكان الصحيح.
  • تتجنّب الخطأ الذي يحذّر منه المصدر.
ما ستقابله من أسماء

كما تظهر تمامًا داخل Hermes.

متغيرات البيئة
  • HERMES_MAIN_CHECKOUT
  • HERMES_TUI_DIR
  • HERMES_GUI_DEPS_CHECKOUT
  • HERMES_DESKTOP_HERMES_ROOT
  • HERMES_DESKTOP_PYTHON
  • HERMES_DESKTOP_IGNORE_EXISTING
  • HERMES_DESKTOP_CWD
خريطة الصفحة

انتقل مباشرة إلى ما تحتاجه.

  1. 01The deps-sharing model
  2. 02`htui` — TUI from the worktree
  3. 03`hgui` — desktop app from the worktree
  4. 04Shared helpers
  5. 05See also
الصفحة الرسمية كاملة

بلا اختصار أو حذف.

النص أدناه منقول من المصدر الرسمي بالإنجليزية حتى تبقى الأوامر والأسماء دقيقة كما هي. قبل كل قسم شرح عربي يوضّح ما بداخله.

The Python core runs fine from any git worktree — cd in and hermes just works. The two TypeScript surfaces do not: ui-tui/ and apps/desktop/ each need a populated node_modules, and a fresh npm ci per worktree is slow and duplicates gigabytes across every branch you have checked out.

htui and hgui are two shell helpers that close that gap. Each launches its surface from the current worktree while borrowing node_modules from one canonical checkout — so a throwaway branch costs a symlink, not an install.

They're developer conveniences, not shipped commands. Drop them in ~/.zshrc; adapt paths to taste.

The deps-sharing model

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه. تذكير: تنزيل Hermes وتجهيزه على جهازك، مع كل ما يحتاجه ليعمل.

One checkout is the deps checkout — the one place you actually run npm install. Every other worktree links against it, and only re-installs locally when its lockfile diverges (a branch that bumps a dependency must not silently run against stale packages).

MERMAID6 أسطر
flowchart TD
    A[htui / hgui in a worktree] --> B{package-lock.json<br/>matches deps checkout?}
    B -- yes --> C[symlink node_modules<br/>from deps checkout]
    B -- no --> D[local npm ci<br/>in this worktree]
    C --> E[launch surface]
    D --> E

Two env vars name the canonical checkout:

VariableMeaning
HERMES_MAIN_CHECKOUTThe deps checkout — where node_modules really lives, and whose .venv/bin/python runs the backend.
HERMES_GUI_DEPS_CHECKOUTWhere the desktop deps (apps/desktop/node_modules) live. Defaults to HERMES_MAIN_CHECKOUT; override only if you keep desktop deps elsewhere.

Neither is read by Hermes itself — they're private to these helpers. The variables Hermes does read are covered in Environment Variables.

`htui` — TUI from the worktree

فيه تحذير مهم. اقرأه قبل أن تنفّذ أي شيء من هذا القسم. نصّ التحذير من المصدر مذكور أسفل هذا الشرح.

The Ink TUI has a dev path already: hermes --tui --dev runs the TypeScript sources via tsx instead of the prebuilt bundle. htui is a one-liner over it that also points the run at the current worktree's ui-tui/:

Shell6 أسطر
htui() {
  local root
  root="$(_hermes_root)" || { echo "htui: not in a Hermes checkout" >&2; return 1; }
  ( cd "$root" && PYTHONPATH="$root" \
      "$HERMES_MAIN_CHECKOUT/.venv/bin/python" -m hermes_cli.main --tui --dev "$@" )
}

--dev compiles from source, so it links ui-tui/node_modules from HERMES_MAIN_CHECKOUT when the root lockfile matches and installs locally otherwise (see _hermes_root / linking helpers ↗).

`hgui` — desktop app from the worktree

جدول مرجعي. لا تقرأه كله، ابحث عن السطر الذي يخصّك فقط.

The desktop app is heavier: it needs node_modules at both the repo root and apps/desktop/, a Vite dev server pinned to port 5174, and a Python backend. hgui wires all of it against the current worktree:

Shell28 سطرًا
hgui() {
  local root deps desktop
  root="$(_hermes_root)" || { echo "hgui: not in a Hermes checkout" >&2; return 1; }
  deps="${HERMES_GUI_DEPS_CHECKOUT:-$HERMES_MAIN_CHECKOUT}"
  desktop="$root/apps/desktop"

  # Borrow deps when locks match; otherwise install locally in the worktree.
  if cmp -s "$root/package-lock.json" "$deps/package-lock.json"; then
    _hermes_link_deps "$desktop" "$deps/apps/desktop"
    _hermes_link_deps "$root" "$deps"
  else
    ( cd "$root" && npm ci ) || return 1
  fi

  # Vite is fixed at 5174 — evict a stale session from another hgui.
  lsof -t -i:5174 >/dev/null 2>&1 && killport 5174

  # Electron often survives Ctrl+C without reaping its ephemeral backends.
  trap '_hermes_gui_cleanup "$root"' INT TERM EXIT

  ( cd "$desktop"
    export PATH="$root/node_modules/.bin:$PATH"
    HERMES_DESKTOP_HERMES_ROOT="$root" \
    HERMES_DESKTOP_PYTHON="$HERMES_MAIN_CHECKOUT/.venv/bin/python" \
    HERMES_DESKTOP_IGNORE_EXISTING=1 \
    HERMES_DESKTOP_CWD="$root" \
    npm run dev )
}

The desktop env vars it sets are all real backend-resolution knobs:

VariableRole in hgui
HERMES_DESKTOP_HERMES_ROOTRuns the backend from this worktree, not the packaged/PATH hermes.
HERMES_DESKTOP_PYTHONReuses the deps checkout's venv instead of re-resolving a Python.
HERMES_DESKTOP_IGNORE_EXISTINGIgnores any hermes on PATH so it can't shadow the worktree.
HERMES_DESKTOP_CWDOpens the desktop chat rooted at the worktree.

Two footguns hgui handles that a bare npm run dev does not:

  • Port 5174 is fixed. A second hgui collides with the first's Vite server; the helper kills the stale one first.
  • Orphaned children. Electron frequently survives Ctrl+C through concurrently without reaping the ephemeral dashboard --port 0 backend or the Vite process. The EXIT/INT/TERM trap runs a cleanup that terminates the Electron shell, the :5174 listener, and any --port 0 dashboard it spawned.

Shared helpers

شرح للفكرة نفسها. اقرأه ببطء، فبقية الأقسام تبني عليه.

Both functions resolve the enclosing checkout and link deps the same way:

Shell21 سطرًا
# The enclosing worktree, verified as a real Hermes checkout.
_hermes_root() {
  local root
  root="$(git rev-parse --show-toplevel 2>/dev/null)" || return 1
  [[ -f "$root/hermes_cli/main.py" && -d "$root/ui-tui" ]] && print -r "$root"
}

# Symlink node_modules from the deps checkout — never over an existing tree.
_hermes_link_deps() {
  local target="${1%/}" source="${2%/}"
  [[ -d "$source/node_modules" ]] || return 1
  [[ -e "$target/node_modules" ]] || ln -s "$source/node_modules" "$target/node_modules"
}

# Reap ephemeral backends Electron leaves behind on exit.
_hermes_gui_cleanup() {
  local root="$1"
  [[ -n "$root" ]] && pkill -TERM -f "${root}/apps/desktop/node_modules/electron" 2>/dev/null
  lsof -t -i:5174 >/dev/null 2>&1 && killport 5174
  pgrep -f 'hermes_cli\.main.*dashboard.*--port 0' 2>/dev/null | xargs -r kill -TERM 2>/dev/null
}

killport is a small helper of your own (lsof -ti:$1 | xargs kill); substitute your preferred incantation.

See also

إعدادات تضبطها مرة وتنساها. غيّر واحدًا في كل مرة حتى تعرف أثر كل تغيير. تضبط HERMES_TUI_DIR خارج المحادثة، في بيئة التشغيل.

اختبار الفهم

4 أسئلة إجاباتها كلها في هذه الصفحة.

كل خيار اسم حقيقي من توثيق Hermes. حتى الخيارات الخاطئة حقيقية، لكنها من صفحات أخرى.

1. في جدول هذا الدرس، ما «Role in hgui» المقابل لـ«HERMESDESKTOPPYTHON»؟
2. أي متغير بيئة من التالي يظهر فعليًا في هذا الدرس؟
3. ما التحذير الذي يذكره المصدر في هذا الدرس؟
4. أي عنوان من التالي لا يظهر في هذا الدرس؟