libwdi requires admin privileges to install WinUSB driver. Previously
the script ran as the current user which silently succeeded but the
driver was not actually installed.
Now runs the Python script elevated via Start-Process -Verb RunAs,
which triggers a UAC prompt. Also adds os.add_dll_directory() to
ensure kp can find libwdi.dll, and writes results to a temp file
since elevated process output is not capturable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The KneronPLUS wheel bundles libwdi.dll and provides
kp.core.install_driver_for_windows() which handles WinUSB driver
installation internally. This replaces the unreliable pnputil +
self-signed INF approach that failed due to unsigned INF rejection.
Changes:
- Split USB setup into two steps: "Setting up USB library" (extract
libusb DLL + driver files) and "Installing USB device driver"
(runs after Python/kp are installed)
- New installKneronDriverViaSDK() calls kp SDK to install WinUSB
for KL520, KL720, and KL720_LEGACY product IDs
- Driver files still extracted as manual Zadig fallback
- macOS/Linux: installUSBDriver() is a no-op
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Go raw strings (backtick-delimited) cannot contain backticks, so
PowerShell's backtick-n newline literal breaks the Go compiler.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Clean old certs from all stores before creating new one
- Use '& certutil.exe' syntax in PowerShell for reliable execution
- Write results to temp file (elevated process stdout not capturable)
- Try pnputil /force flag as fallback if signature check fails
- Report actual pnputil error message instead of silent skip
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the WinUSB driver installation silently failed because it
needed admin privileges. Now:
- All admin operations (cert creation, certutil, pnputil) run in a
single elevated PowerShell script via Start-Process -Verb RunAs,
triggering one UAC prompt
- If the user declines UAC, a clear error message is shown with
instructions to use Zadig as a manual fallback
- If driver files are not bundled, error explains what to do
- installLibusb now propagates the error instead of swallowing it
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add installer/drivers/ with all Windows USB driver dependencies:
- kneron_winusb.inf (KL520/KL720 WinUSB driver)
- amd64/WdfCoInstaller01011.dll (WDF co-installer)
- amd64/winusbcoinstaller2.dll (WinUSB co-installer)
- libusb-1.0.dll (USB communication library)
Previously these files were sourced from external local_service_win/
directory which may not exist on build machines. Now all build
scripts (Makefile, build-installer.ps1) source from the repo.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add installer/wheels/{windows,macos,linux}/ with platform-specific
KneronPLUS SDK wheels so any machine can build installers without
needing external wheel files.
- Windows: KneronPLUS v3.1.2 (3.6 MB, with .dll)
- macOS: KneronPLUS v2.0.0 (151 KB, with .dylib)
- Linux: KneronPLUS v2.0.0 (159 KB, with .so)
Updated all build scripts (Makefile, build-installer.ps1,
build-installer-linux.sh) to source wheels from the repo instead
of external directories. Updated installer/app.go to look for
Linux wheels in scripts/linux/ subdirectory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add scripts/linux/ directory for Linux-specific KneronPLUS wheel
- installer/app.go: add Linux case to wheel selection (scripts/linux/)
- build-installer-linux.sh: search ~/Downloads/KL520Web/package/ubuntu/
and kneron_plus source dir for KneronPLUS*.whl
- Makefile: add Linux wheel copy to installer-payload target
Without the kp module, devices can be scanned (via pyusb fallback)
but cannot connect, load models, or run inference.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The bridge script was missing pyusb import and _scan_with_pyusb()
fallback, so scan returned empty on systems without the KneronPLUS
SDK (kp module). Now falls back to pyusb for device detection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without udev rules, only root can access Kneron USB devices, so the
web server running as a normal user cannot scan/connect to devices.
Adds /etc/udev/rules.d/99-kneron.rules granting MODE=0666 for
KL520 (PID 0x0100), KL720 KDP (PID 0x0200), KL720 KDP2 (PID 0x0720).
Applied in both GUI installer (platform_linux.go installLibusb) and
CLI installer (install.sh setup_libusb).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The server reads relay config from CLI flags, not config.json.
Auto-restart services (systemd on Linux, launchd on macOS, Registry
Run key on Windows) were launching the server without relay args,
so the tunnel never connected.
Now all three platforms pass --relay-url and --relay-token to the
server binary in their auto-restart configuration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
PRD changes:
- F16: Add Linux platform support, 5-step install, App Alias detection
- F17: Add Linux as target platform, Linux build requirements,
headless server mode, python3-venv auto-fix, --source winget
TDD changes:
- 11.2: Replace outdated .dmg/.msi/.deb with actual CLI/GUI install methods
- 11.3: Update GoReleaser config to match actual .goreleaser.yaml
- 11.4: Replace outdated Makefile with current targets including
installer-linux and build-installer scripts
- 11.5: Add build-installer-linux.sh and kneron_detect.py to script table
- Installation steps table: Add Linux column with apt-get/systemd details
- Python auto-install: Document autoInstallPython3() per-platform pattern,
findPython3() search order, ensurepip fallback on Linux
- Scripts dir: Add KL720 firmware, kneron_detect.py, update_kl720_firmware.py
- Uninstall: Add Linux systemd cleanup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Linux server binary is built with CGO_ENABLED=0 and -tags notray,
so --tray is not available. The systemd service and LaunchServer now
start the server without the --tray flag on Linux.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
On Ubuntu/Debian, python3 is often pre-installed but python3-venv is
not, causing venv creation to fail with "ensurepip is not available".
Now detects this error and auto-installs the matching python3.x-venv
package via apt-get before retrying.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Detect webkit2gtk-4.1 and add webkit2_41 build tag for Wails
- Accept either webkit2gtk-4.0 or 4.1 in prerequisite check
- Use CGO_ENABLED=0 + notray for server build (consistent with GoReleaser)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add scripts/build-installer-linux.sh for building the Wails GUI
installer on Ubuntu (checks for GTK3 and WebKit2GTK dependencies)
- Refactor autoInstallPython3() into per-platform files so each OS
can auto-install Python 3 (winget on Windows, apt-get on Linux,
brew on macOS)
- Add installer-linux target to Makefile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The msstore source can fail with certificate error 0x8a15005e on
some Windows machines, causing Python, ffmpeg, and yt-dlp installs
to fail even though the packages exist in the winget source.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Windows 10/11 ships with App Execution Aliases that redirect python.exe
to Microsoft Store. The installer now detects this stub and provides
specific guidance to install real Python and disable the alias.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
6-step spotlight tour (Scan → Connect → Manage → Flash → Workspace → Inference)
with step completion validation, polling auto-detection, and i18n support (en/zh-TW).
Triggered from onboarding dialog or header help button.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace DiInstallDriverW (failed with 0xE000022F / no catalog) with
proven approach: create self-signed code signing cert via PowerShell
New-SelfSignedCertificate, install to TrustedPublisher + Root stores
via certutil, then use pnputil /add-driver /install which accepts
the unsigned INF when cert is trusted. Removes syscall/unsafe deps.
Tested successfully on Windows: KL520 + KL720 drivers installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New flow: PowerShell New-SelfSignedCertificate → install to
TrustedPublisher/Root stores → create .cat via inf2cat/makecat/
New-FileCatalog → sign with signtool/Set-AuthenticodeSignature →
pnputil /install. Falls back to SetupAPI DIF_INSTALLDEVICE.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse MULTI_SZ hardware IDs correctly (was only reading first string)
- Add device listing step to show all Kneron devices with Hardware IDs
- Case-insensitive HWID matching
- Better debug output at each SetupAPI step
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Method 3 uses SetupDiGetClassDevs + SetupDiEnumDeviceInfo to find the
exact device node, then SetupDiBuildDriverInfoList + DIF_SELECTBESTCOMPATDRV
+ DIF_INSTALLDEVICE to install driver directly on the device, bypassing
the catalog signature check that blocks Methods 1 and 2.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Test both methods: UpdateDriverForPlugAndPlayDevicesW (with Hardware ID
matching) and DiInstallDriverW. Also includes go.mod and pre-built exe.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Build: already cross-compiled as test_driver_install.exe
Usage: .\test_driver_install.exe "C:\path\to\kneron_winusb.inf"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pnputil rejects unsigned INF, installer_x64.exe is not a CLI tool.
Switch to calling Windows DiInstallDriverW from newdev.dll directly,
which can install unsigned drivers with a user confirmation dialog.
Uses DIIRFLAG_FORCE_INF flag to force INF installation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
pnputil rejects unsigned INF files ("does not contain digital signature
information"). Replace with installer_x64.exe (libwdi-based) from
Kneron SDK, which handles driver signing automatically with a
self-signed certificate.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When connect fails, the partially-created DeviceGroup object could
trigger an access violation in __del__ during GC. Explicitly set
_device_group = None before each retry and in the except handler.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bundle WinUSB driver INF + co-installer DLLs in installer payload.
During USB driver setup step, extract driver files and run pnputil to
install the WinUSB driver for all Kneron devices (KL520 VID_3231&PID_0100,
KL720 VID_3231&PID_0200, KL720v2 VID_3231&PID_0720).
This eliminates the need for manual Zadig installation, which was the
root cause of KP_ERROR_CONNECT_FAILED_28 on Windows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Retry connect up to 3 times with 2s delay and re-scan between attempts
- Re-scan refreshes USB device handles which can resolve timing issues
- Add Windows-specific hint about Zadig/WinUSB driver in error message
- Firmware reload reconnect also gets retry + fallback to without_check
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add "Installing media tools" step to the installer that automatically
installs ffmpeg and yt-dlp if not already present on the system.
Uses winget (Windows), Homebrew (macOS), or apt-get (Linux).
Non-critical step — installation continues even if this fails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
KL520 in USB Boot mode reports is_connectable=False, which is normal -
firmware must be loaded first. The previous code rejected the connection
attempt early. Now we use connect_devices_without_check() for devices
that are not yet connectable, then proceed with firmware loading.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The server's kneron_bridge.py requires the `kp` (KneronPLUS) module
to detect devices. Without it, HAS_KP=False and scan returns empty.
Changes:
- build-installer.ps1: copy KneronPLUS*.whl to payload/scripts/
- Makefile: same for macOS builds
- CI workflows: same for GitHub/Gitea Actions
- installer app.go: pip install the bundled wheel after requirements.txt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tray icon:
- Embed proper ICO files (green=running, red=stopped) instead of
generic IDI_APPLICATION icon
- Switch icon dynamically based on server state
Console window:
- FreeConsole() to fully detach from parent console
- CREATE_NO_WINDOW flag on child server process to prevent
black console window from appearing
Device detection:
- ResolvePython: add Windows venv paths (Scripts/python.exe) and
%LOCALAPPDATA%\EdgeAIPlatform\venv, fallback to exec.LookPath
- DetectDevices + startPython: prepend install dir to PATH so
libusb-1.0.dll is found by pyusb/kp SDK
- Also hide "cmd /c start" console when opening browser
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
kneron_detect.py now prepends the install directory to PATH before
importing pyusb, so libusb-1.0.dll in the install dir is found.
DetectHardware() also sets PATH in the subprocess environment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- webgui.go: Native Windows tray icon + right-click popup menu using
pure syscall (Shell_NotifyIconW, CreatePopupMenu, etc.)
- No CGO required, no external dependencies
- Shows server status, Start/Stop, Open Dashboard, Quit
- Hides console window on startup
- Handles OS signals and Windows session end
- webgui_other.go: Stub for non-Windows notray builds
- Remove webgui_html.go (browser-based approach no longer needed)
- Fix auto-start: replace schtasks (fails on Chinese Windows) with
Registry Run key (HKCU\...\Run) which works without admin and
has no locale encoding issues
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add a CGO-free alternative to the systray-based --tray mode. When
launched with --gui, the server starts a lightweight HTTP control panel
in the browser where users can start/stop the server, open the dashboard,
and view relay status.
New files:
- server/tray/webgui.go: HTTP API backend + child process management
- server/tray/webgui_html.go: Embedded HTML control panel
Modified:
- config.go: Add --gui flag
- main.go: Route --gui to RunWebGUI()
- tray.go: Add RunWebGUI stub for tray-enabled builds
- installer: Windows uses --gui instead of bare launch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove --tray flag from LaunchServer() on Windows (notray build)
- Switch schtasks from PowerShell Register-ScheduledTask to schtasks CLI
for Chinese Windows compatibility
- Remove /RL HIGHEST from schtasks (requires admin privileges)
- Add install log output to %TEMP%/edgeai-install.log
- Add critical flag to install steps (critical failures abort)
- Fix extractDir: create parent dirs before writing files
- Improve findPython3: skip Windows Store stub, auto-install via winget
- Enhance installLibusb: extract bundled DLL, fallback to winget
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- installLibusb now extracts libusb-1.0.dll from payload to install dir
- Falls back to winget, then shows Zadig download link
- checkLibusbInstalled also checks install directory
- CI workflow copies libusb-1.0.dll into payload during staging
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findPython3: skip Windows Store stub (WindowsApps), search common
install locations (LocalAppData/Programs/Python/PythonXXX)
- installAutoRestart: use schtasks instead of PowerShell
Register-ScheduledTask to avoid XML parsing errors on non-English
(Chinese) Windows
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
extractDir was writing files without creating parent directories first,
causing "The system cannot find the path specified" errors on Windows
when models.json was walked before the data/ directory entry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Installer now writes a detailed log to %TEMP%/edgeai-install.log
(or /tmp/edgeai-install.log on macOS/Linux) with OK/FAIL status for
each step. Log path is shown on completion and in error messages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When Python 3 is not found during installation on Windows, the installer
now automatically attempts to install it using winget (Python.Python.3.12).
Falls back to manual install prompt if winget is unavailable.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Previously all step errors were treated as warnings and installation
continued silently. Now critical steps (create dir, extract binary,
extract data/scripts, write config) will abort with an error message.
Non-critical steps (libusb, python venv, symlink, auto-start) still
warn and skip.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Added winget install commands and verification steps for Go, Node.js,
Git, pnpm, and Wails CLI in TDD section 11.7.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>