Skip to content

Releases: libxa-framework/libxa-desktop-releases

Libxa Desktop 0.12.0

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 05 Oct 06:07

Libxa Desktop 0.12.0 - security hardening and service fixes. Windows 10/11 x64.

Security

  • MySQL and nginx listened on every network interface. A fresh MariaDB has
    a passwordless root, so anyone on the same Wi-Fi could log in, and every
    local project was readable from the network. Both now bind 127.0.0.1.
    A new Settings option, Allow other devices on the network, restores the old
    behaviour for testing from a phone.
  • "Open path" could launch executables. The renderer-supplied path went
    straight to shell.openPath; executable types are now refused. Clearing a
    site log is limited to log files a site actually owns, instead of truncating
    any path it is handed.
  • A settings patch from the renderer was written to disk unchecked. Ports,
    the domain suffix and binary paths are validated, unknown keys are dropped,
    and duplicate ports are rejected with a message naming both.

Fixed

  • Restarting MySQL left it stopped. stop returned before the process had
    exited, so the restart's start saw it still running and did nothing, and
    the delayed exit then marked it stopped. stop now waits for the process.
  • MySQL was force-killed on every stop and on quit, which is how an InnoDB
    data directory gets damaged. It is asked to shut down (mariadb-admin shutdown) first and only killed if it refuses. Quitting waits for services
    to stop, with a cap, instead of exiting under them.
  • Double-clicking Start spawned a service twice, and the second copy failed
    to bind and was reported as a crash of the first. Concurrent starts now join.
  • php-cgi exited after 500 requests on Windows, leaving nginx answering 502
    until PHP was restarted by hand. PHP_FCGI_MAX_REQUESTS=0 is now set.
  • One php-cgi meant one request at a time, so a page that called its own
    site (WordPress loopback, a local API call) waited on itself forever. Each
    PHP version now runs a pool of four behind an nginx upstream, and a worker
    that dies is replaced. Pool changes are serialised: concurrent refills used
    to spawn duplicate workers that outlived the app.
  • PHP ports collided with Xdebug. 8.0 on 9000 and 8.3 on 9003 sat on
    Xdebug's default ports. The range now starts at 9500.
  • A site pinned to an uninstalled PHP version got a 502. It is routed to the
    default version, the site's PHP picker says "(not installed)", and an
    uninstalled default is replaced automatically.
  • Parking a folder, removing a site or changing PHP did nothing until nginx
    was restarted.
    nginx is reloaded in place (after nginx -t, so a bad config
    leaves the working one serving). Changed ports get a real restart that checks
    the new port first, and Settings no longer tells you to restart by hand.
  • Orphaned nginx was never reaped. The check looked for logs/nginx.pid
    while the config writes nginx.pid, so after a crash every launch moved the
    whole stack to another port.
  • PATH_INFO was dropped (/index.php/route returned 404), and large
    Ignition/Whoops pages failed with "upstream sent too big header". Both fixed;
    HTTP_PROXY is no longer passed through (httpoxy).
  • Python installs never refreshed the Python list, because every install
    rescanned PHP. Each kind rescans its own list.
  • Installing over or removing a running service failed on locked files. The
    service is stopped first and restarted afterwards.
  • Large downloads failed on a dropped connection ("terminated"). They now
    retry with a Range resume, and the checksum covers the finished file.
  • A runtime that cannot start (missing Visual C++ runtime) installed
    "successfully" and then never appeared.
    Installs are smoke-tested and say
    what is missing.
  • PATH edits flattened %SystemRoot%-style entries into literal paths and
    changed the registry value type, because .NET returns the expanded string.
    The registry is now read and written directly, as REG_EXPAND_SZ.
  • The hosts file could be wiped. If it could not be read (antivirus lock),
    the rewrite proceeded from an empty string and dropped every other entry.
    An unreadable file now aborts the write.
  • Closing the app killed the tray with it; an optional Keep running in the
    tray
    setting hides the window instead. Tray actions no longer crash the main
    process when a service is not installed, and the Sites and PHP menus refresh
    when they change.
  • The site preview was blocked by the renderer's CSP, and the Mailpit inbox
    badge could never load for the same reason. The preview is allowed, and the
    count is fetched from the main process.
  • The site log viewer read the whole file to show its tail, once a second.
  • A failed scaffold left a half-created project that blocked every retry.
  • The window's log file grew without bound. It rotates at 5 MB.
  • Smaller: the Settings page saved a stale copy of settings changed elsewhere
    (switching PHP from the tray, then saving, switched it back); the HTTPS port
    was not editable; Laravel and WordPress projects ignored a non-default MySQL
    port; a Laragon/WAMP PHP layout was never discovered; MariaDB under Program
    Files was only found at hard-coded versions; the Composer shim failed when
    PHP was not on PATH; MariaDB [Warning] lines showed as errors; the Mailpit
    log filter was missing; Services offered "Start" while a stop was in flight.

Libxa Desktop 0.11.0

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 19 Aug 11:19

Your application's log, in the site pane. Plus Symfony and WordPress starter kits.

Application logs

A new Logs tab beside Share shows the framework's own log — the stack trace you actually want when something breaks, not the nginx access log.

Where that lives depends on the framework, so it's derived from the detected type rather than guessed:

Framework Location
Laravel storage/logs/
LibxaFrame src/storage/logs/
Symfony var/log/
WordPress wp-content/debug.log
Plain PHP logs/, log/
  • Follow keeps the newest line in view as the file grows
  • Filter narrows to matching lines
  • Clear empties the file without deleting it, so the framework keeps writing
  • Lines are coloured by level, parsed from the entry header

Daily-rotated files are listed too. A project using Laravel's daily driver has no laravel.log at all, and offering only that name would show an empty panel on a site that's logging perfectly well.

Two limits worth knowing: only the last 256 KB is read — an unrotated laravel.log reaches hundreds of megabytes and loading one would take the window down, so the panel says tail only when it has trimmed. And the file is polled once a second rather than watched through the OS notification API, because fs.watch on Windows misses writes from processes that hold the handle open — exactly what a logging framework does.

Two more starter kits

Kit Source
Symfony composer create-project symfony/skeleton
WordPress The official archive from wordpress.org

WordPress is the odd one out. It isn't a Composer package in any form its own users would recognise, so the release zip is downloaded, checked against the SHA-1 wordpress.org publishes beside it, and unwrapped — the archive contains a wordpress/ folder and the project is its contents, not a folder inside a folder.

Create a database for it first; the Environment tab does that in one click.

Install

Download libxa-desktop-0.11.0-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.10.1

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 19:45

Everything a project needs before it runs — its .env and its database — now lives beside the site. Plus a fix for installing Mailpit.

Fixed: Mailpit would not install

Installing Mailpit always failed:

Checksum mismatch for mailpit-windows-amd64.zip.
Expected , got e4815d2c961a4ad024f4d942d0d286fd7b7da49c49fc7f01c565ff296bd3fdce.

The download was never at fault — those bytes hash to exactly that value. The comparison was.

Mailpit publishes no checksum file, so its entry returned an empty string. The verify step guarded against null, and an empty string is not null, so it compared the real hash against "" and could only ever fail.

The check is now explicit about all three cases rather than inferring them from one nullable field: no published checksum skips the comparison and logs what it saw, a genuine mismatch still discards the download, and an entry that claims to be verifiable while resolving no checksum fails loudly — instead of silently installing something unverified while the interface says otherwise.

Environment tab

Each site gains an Environment tab.

  • .env table with credential-looking values masked until you ask
  • Raw editor, keeping the previous version as .env.libxa-backup
  • Create from example — the state every freshly cloned repository is in
  • Use local mail points this project's MAIL_* at the local catcher

The mail rewrite now works on any project with a .env, not only ones created here. Existing keys are replaced in place rather than appended; a commented # MAIL_HOST= is left as documentation, and nothing outside the managed keys is touched — including values containing # or =.

Database

  • Name suggested from the site — my-app.test becomes my_app
  • Creating one also writes DB_DATABASE into the site's .env
  • Listed with table count and size; the server's own are hidden and undroppable

Creating a database and telling the application its name are one task split across two tools. Doing them separately is how a project ends up pointed at a database that was never created.

Databases are utf8mb4 explicitly, because the server default is still latin1 on some builds. Names are validated rather than escaped — SQL has no placeholder syntax for an identifier.

About

A new About page covering the product, VYLOXI — Empowering Your Digital Future — and the head of development, with live counts of the sites and runtimes on your machine. The photograph is bundled with the app, so the page renders identically with no network.

Install

Download libxa-desktop-0.10.1-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.9.0 — Mail

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 15:54

Your sites can now send mail, and you can read it.

Mail

Mailpit joins PHP, Nginx and MySQL as a managed service. It accepts everything your sites send on 127.0.0.1:1025 and shows it in an inbox at http://127.0.0.1:8025.

  • Live message count in the Services tab, and an Open inbox button
  • New sites are pointed at it automatically — a project created here can send mail with no setup
  • Copyable .env block for projects that were not created here
  • SMTP and inbox ports configurable in Settings

Why this matters

A framework's stock .env names a mail host that does not exist on a developer machine. The first mail a new project sends fails with a connection error, or vanishes — so "register a user" appears broken for a reason that has nothing to do with your project.

Details worth knowing

Bound to localhost only. Captured mail is real password resets and customer test data; it should not be readable from whatever network your laptop is on.

The .env rewrite is careful. Existing MAIL_* keys are replaced in place rather than appended — a duplicate key wins in some parsers and loses in others. A commented # MAIL_HOST= is treated as documentation and left alone, and nothing outside the managed keys is touched, including passwords containing # or =.

Mailpit publishes no checksum file, so it is marked verification: none and the installer shows you that before you agree, rather than implying a guarantee that isn't there.

Documentation

New FEATURES.md documents the whole app — sites, sharing, services, mail, PHP, Composer, Node, Python, PATH handling, certificates and storage locations — including the reasoning behind the decisions that look surprising:

  • why sharing forwards to nginx rather than the project directory
  • why enabling a PHP extension also enables extension_dir
  • why Python comes from python-build-standalone instead of python.org
  • why runtimes are reached through junctions instead of PATH entries

Install

Download libxa-desktop-0.9.0-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.8.3

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 14:52

Two bugs that kept Node and PHP resolving to the old install even after the elevated fix reported success.

Shims left as empty directories

The elevated step created a real, empty directory exactly where the junction had to go. That directory then sat at the front of the machine PATH resolving nothing — so the runtime you replaced kept winning, and the panel had no way to explain why.

Now only the shim's parent is created; the junction is made in one place, a stray plain directory is cleared out of the way, and the result is verified afterwards (mklink can report success while leaving nothing usable behind).

Machines already in this state repair themselves. Opening the PHP, Node or Python tab recreates a shim that exists but isn't a link — safe, because it only restores a link you already asked for.

pip resolved to the wrong Python

python-build-standalone ships pip as an importable module but doesn't generate its console scripts, so Scripts\ contained only a placeholder. The directory was on PATH, and ahead of other installs — yet pip still resolved elsewhere while python -m pip worked fine, which is a genuinely confusing way to fail.

ensurepip doesn't help (it sees pip already installed). Reinstalling the pip package is what regenerates the scripts, and activating a Python now does that first.

Verified end to end

On a machine where all three were shadowed by machine-scope installs:

before after
node 25.6.0 26.7.0
npm — 11.19.0
php 8.4.19 8.5.9
python 3.14.2 3.10.21
pip 25.3 (wrong Python) 26.2.1

All five now resolve through the shims, matching what the app shows.

Install

Download libxa-desktop-0.8.3-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.8.2

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 11:16

UI fix for the PATH status panel added in 0.8.1.

What was wrong

The status text rendered as one run-on paragraph:

python resolves to 3.14.2 — not the version selected hereC:\Python314\python.exepip 25.3 — C:\Python314\Scripts\pip.exeC:\Python314 is in the system PATH…

Every line was there and every line was correct — they just had no line breaks. The health-* classes carry no display rule, and the rest of the app uses <div> for them, but the panels added over the last few releases used <span>, so each line rendered inline.

Now each fact sits on its own line: what python resolves to, the binary path, the pip that came with it, and the explanation of why a system-PATH install wins.

Fixed only in the components that introduced it. The pre-existing inline <span className="health-label"> usages in the runtime rows, phpMyAdmin panel and Sites page are laid out beside other inline content, so a blanket CSS rule would have broken them.

Also

The three switch labels no longer say "(adds it to your user PATH)". Since 0.8.1 the runtime is reached through a fixed shim directory, and where the PATH entry lands depends on whether something is shadowing from machine scope — so the parenthetical was misleading.

Install

Download libxa-desktop-0.8.2-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.8.1

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 10:41

Bug fix: switching PHP, Node or Python version now actually changes what your terminal runs.

What was broken

Switching version updated the UI but node -v and python --version reported the same thing as before. The cause was a wrong assumption in the PATH code — it wrote only to your user PATH.

Windows builds the effective PATH as machine PATH first, then user PATH. On a normal machine:

node    -> C:\Program Files\nodejs      in SYSTEM path
python  -> C:\Python314                 in SYSTEM path

Both are machine-scope, so nothing written at user level could ever outrank them. The feature could not have worked.

The fix

Runtimes are no longer put on PATH directly. Each gets a fixed directory holding a junction to the active install:

%LOCALAPPDATA%\Programs\libxa\shims\node  ->  the selected Node

Switching repoints the junction, so PATH is written once and never again — switches are instant and need no prompt. Junctions require no elevation, and because the target is a real directory, the executable behind one can still be spawned without a shell (a .cmd shim could not).

When an install still wins

If the winning entry is machine-scope, no user-level change can beat it. That case is now detected and named — the panel tells you which directory is winning, that it lives in the system PATH, and why that matters — with a Fix as administrator button that puts the shim directory first. One prompt, once; switches afterwards need none.

It is never attempted silently.

Also fixed

Python registered two PATH entries under a single settings key, so the second registration treated the first as the previous entry and removed it — the Scripts directory holding pip.exe was added and immediately dropped.

Install

Download libxa-desktop-0.8.1-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.8.0

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 10:20

Python joins PHP and Node as a fully managed runtime.

Python

A new Python tab: install any version, switch between them, remove them, and put the active one on your PATH.

> python --version
Python 3.13.15
> pip --version
pip 26.2.1

Both follow the version you select. Same rules as PHP and Node — your user PATH only, no administrator prompt, switching repoints the same entries, and only what this app added is ever removed.

Versions offered: 3.14, 3.13, 3.12, 3.11, 3.10, each resolving to the newest patch automatically.

Where the builds come from

Not python.org, and that was a deliberate call after testing both alternatives:

  • python.org's Windows download is an interactive .exe that can't be driven unattended into a per-user directory.
  • Its "embeddable" zip deliberately omits pip and venv. Getting pip working needs import site uncommented in a ._pth file plus a get-pip bootstrap — and venv is absent entirely. A Python that can't create a virtual environment is half a Python.

So Python comes from python-build-standalone, the same relocatable CPython builds uv uses. pip and venv both work out of the box, and the project publishes a SHA256SUMS file — so downloads are verified, not merely fetched over TLS.

Details worth knowing

  • Two PATH entries, not one. The interpreter sits at the install root but pip.exe lives in Scripts\. Registering only the root gives you a working python beside a missing pip, so both are handled.
  • The Microsoft Store stub is skipped. The python.exe in WindowsApps isn't an interpreter — it opens the Store — and probing it hangs. If one is winning on your PATH, the panel says so and tells you how to fix it.
  • Tarball downloads are unpacked with the bsdtar Windows has shipped since 10 1803, rather than adding a tar dependency for one runtime.

Install

Download libxa-desktop-0.8.0-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.7.0

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 09:50

Node joins PHP as a global runtime, and Composer installs from inside the app.

Global Node

Use globally on the Node tab now puts the selected runtime on your PATH:

> node -v
v25.6.0
> npm -v
11.8.0

Both follow the version you pick — one PATH entry covers node, npm and npx, since they share a directory. npm's version is shown separately because it moves independently of Node's.

Same rules as PHP: your user PATH only, so no administrator prompt; switching version repoints the same entry; and only the entry this app added is ever removed.

Composer

The PHP tab can now install Composer if you don't have it.

  • Downloads the official PHAR and verifies the SHA-256 the project publishes beside it
  • Proves it runs before it becomes the installed copy
  • Adds composer to your user PATH — no administrator rights
  • Update and Remove for the copy this app manages

It lives with the PHP tooling rather than in a downloads list because it isn't independent of PHP: Composer is a PHAR that runs on whichever version you've activated. Enable an extension in php.ini and Composer sees it immediately; switch PHP version and Composer follows, without reinstalling.

An existing Composer from the official installer, Scoop or XAMPP is detected and left alone — the app reports it rather than overwriting it, and offers a managed copy only if you want one.

Install

Download libxa-desktop-0.7.0-x64.exe below. Windows x64. Existing installs update automatically.

Libxa Desktop 0.6.0

Choose a tag to compare

@voukengdongmofrankysteve voukengdongmofrankysteve released this 17 Aug 09:11

Your chosen PHP is now the machine's PHP, and php.ini is editable in-app.

Global PHP

Use globally on the PHP Versions tab now means exactly that. Switch it on and the selected runtime goes onto your PATH, so php -v in any terminal reports the version you picked — not whatever XAMPP left behind.

  • Writes to your user PATH only, so no administrator prompt
  • Switching version repoints the same entry rather than piling up new ones
  • Only ever removes the entry this app added; the rest of your PATH is untouched
  • A status line tells you what php currently resolves to, and warns when another PHP earlier in PATH is winning

php.ini, without the text editor

The usual routine — find php.ini, delete a semicolon, remember extension_dir, restart everything — is now a toggle.

  • Extension toggles for openssl, curl, mbstring, intl, gd, zip, pdo_mysql and the rest
  • loaded / not loaded badges from php -m, so you see what PHP actually loaded, not just what the file asks for
  • Raw editor behind a switch when you need the full file
  • A missing php.ini is created from php.ini-development, which is how a fresh Windows PHP ships
  • Saves are validated by PHP before replacing the live file, and the previous version is kept as a backup
  • PHP reloads immediately, so sites pick the change up without a manual restart

One thing worth knowing

Enabling an extension also enables extension_dir in the same step. On Windows the first half without the second silently does nothing, which is why "I uncommented the line and it still doesn't work" is so common.

The stock php.ini actually ships two commented candidates:

;extension_dir = "./"
;extension_dir = "ext"

Uncommenting the first points PHP at the wrong directory. This release picks the "ext" line explicitly.

Install

Download libxa-desktop-0.6.0-x64.exe below. Windows x64. Existing installs will be offered this automatically.