Skip to content

feat(desktop): embed Vazirmatn + self-heal the asar patch after updates - #2

Merged
programmer-1998 merged 1 commit into
programmer-1998:mainfrom
sadegh19b:feat/vazirmatn-desktop-selfheal
Oct 15, 2026
Merged

programmer-1998 merged 1 commit into
programmer-1998:mainfrom
sadegh19b:feat/vazirmatn-desktop-selfheal

Conversation

@sadegh19b

Copy link
Copy Markdown
Contributor

What

  • Vazirmatn (OFL) embedded in the Desktop UI. The renderer patch now injects an inline base64 @font-face and overrides --font-family-sans with !important (the app sets that variable inline, so !important is required to win). --font-family-mono is left untouched, so code / diffs / shell output stay monospace.
  • Version-aware patch. The injected block carries data-rtl-version="N"; the engine strips a previous patch and re-injects it, so an existing bidi-only patch is upgraded in place instead of being treated as "already patched".
  • <asar>.rtl-stamp (v<version>:<size>:<mtimeMs>) records the patched state and invalidates stale stamps.
  • Self-heal (src/desktop.ts, ensureDesktopPatch). Because app.asar is locked while the Desktop runs, the guard probes writability first and only patches when the app is closed, retrying on a slow timer - so the fix is re-applied automatically after every Desktop auto-update. Wired into the v1 server/CLI plugins and the v2 server/CLI plugins.
  • New desktop option (default true) to opt out of touching app files at all.
  • Tests. Fixed the patch-engine test on Windows (path separator) and added assertions for the font and the version marker.

Why

No plugin hook reaches the Desktop renderer (server hooks are server-side, the CLI plugin is terminal-only, and the "GUI extensions" system is dev-builds-only in the released app), so patching app.asar is the only route. This change keeps that patch applied across updates and gives the UI a proper Persian/Arabic font with no system font install and no network.

Test

npm test -> 19/19 (build + core + patch-engine).

Notes

  • The host needs Node 20+ (the guard shells out to node to run the engine).
  • patch/fonts/Vazirmatn-Variable.woff2 is SIL OFL 1.1; patch/fonts/OFL.txt is included.

Desktop: embed Vazirmatn (OFL) via @font-face and override
--font-family-sans with !important so the whole UI uses it, with no
system font install and no network.

Engine (patch/lib/patch-asar.mjs):
- inject a data-rtl-version marker and upgrade an existing bidi-only
  patch in place instead of no-op'ing
- write <asar>.rtl-stamp = v<ver>:<size>:<mtimeMs> so the guard can
  tell whether the current asar is fully patched

Plugin (src/desktop.ts):
- new ensureDesktopPatch guard: probes writability (the asar is locked
  while the Desktop runs) and re-applies the patch on a slow timer, so
  it self-heals after every app update
- new `desktop` option (default true); false leaves app files alone

Tests: fix patch-engine test on Windows (path separator) and add font
+ version-marker assertions.

Docs: README.md / README.en.md / README.ar.md — the only viable route
is the asar patch (no plugin hook reaches the renderer), self-heal
behavior, the `desktop` option and the Vazirmatn credit.
@programmer-1998
programmer-1998 merged commit 2557ba4 into programmer-1998:main Oct 15, 2026
@programmer-1998

Copy link
Copy Markdown
Owner

Thank you @sadegh19b! Merged. Great work — the embedded Vazirmatn, the version-aware upgrade, and especially the self-heal guard solve the biggest pain point of the desktop patch (re-applying after every auto-update). I did a full review: all 19 tests pass, no security concerns. Small touch-ups on top: removed a stray candidate path, fixed the Windows default path in all three READMEs, and credited you in the fa/en READMEs. Thanks again for the contribution! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants