- Add kill-previous-instance.js with PID lock file under BASE_DIR
- On startup, send SIGTERM to any existing native-host process before binding ports
- Register removePidFile on shutdown and exit so the lock is cleared
- Run "stop any running native host" at the start of install.sh and install.ps1
- Add kill-previous-instance.js to CI syntax check
Write all path variants for every .json in the bundle when building
for win32 (backslash, with/without leading slash) so bundle.read()
returns content regardless of runtime key normalization. Refill empty
or invalid JSON from alternate key or disk before writing variants.
Explicitly write tt-native package.json under Windows path variants
in Fix 1. Document in CHANGELOG.
Use forward-slash addon resolution key for all platforms in the
distributable build so the runtime finds the tt-native prebuild when
the bundle normalizes paths on Windows. Update CHANGELOG and
CONTRIBUTING to document the fix.
After unmount, the runtime may resolve #package with or without a
leading slash. Write the same content to both keys so the .json
loader never gets an empty entry and the host no longer crashes with
"Unexpected end of JSON input" on Windows.
patchBundle so the runtime never gets empty content for that key
(fixes "Unexpected end of JSON input" in Module._extensions..json
when the host is started by the extension on Windows).
- State: treat empty or whitespace-only state.json (and legacy
persist file) as missing and return default state instead of
throwing in JSON.parse.
- State: add ensureStorageDir() and call it from message-router
after setStoragePath so the storage directory exists on fresh
install before any state is loaded or saved.
When building with --all, the bundle used a single addon resolution (darwin-arm64),
so the Linux binary tried to load the wrong prebuild and tt-native failed. Patch
tt-native binding with a nested resolution map (addon → bare → node → platform →
arch) so the runtime selects the correct prebuild per platform; SSH PTY then works
on Linux.
- Firefox rejects native messaging manifest if allowed_origins is present.
Install script now writes Chrome-only manifest (allowed_origins) and
Firefox-only manifest (allowed_extensions) to their respective locations.
- Fix local Firefox manifest by removing allowed_origins.
- Log disconnect reason from port.error (Firefox) in addition to
runtime.lastError (Chrome) so native messaging failures are visible.
- Log getState failures on disconnect for easier debugging.
- Add extension/manifest_firefox.json (no key, moz-extension://*/* for
web_accessible_resources) for correct Firefox MV3 behavior
- Update pack-extension.js: zip excludes manifest_firefox.json; XPI
built separately with manifest_firefox.json as manifest.json
- Update generate-extension-id.js to set gecko.id in manifest_firefox.json
when present (no key in Firefox manifest)
- Document dual-manifest layout and pack/generate-id behavior in CONTRIBUTING.md
Reverts the experimental feature that attempted to serve the dashboard
via a local HTTP server registered as a hardcoded `my.dash.board` virtual
host, intended to satisfy Chrome's PWA "secure origin" installability
requirement. The approach caused proxy connection errors and file-not-found
issues that were not worth resolving.
Removed: native-host/dashboard-server.js, native-host/test-chain.mjs
Reverted: startup.js, message-router.js, virtual-hosts.js, index.js,
build-distributable.js, extension/pages/virtual-hosts.js,
CI workflows (ci.yml, release.yml)
Fix "Proxy error: connection reset by peer" caused by dashboard-server.js
looking for files in native-host/ instead of extension/dashboard/. Remove
the devBasePath parameter and resolve DEV_DASHBOARD_DIR directly from
__dirname so dev and distribution mode both find the correct files.
Fix all manifest warnings (start_url/id/scope/protocol_handlers ignored)
by reverting manifest.webmanifest to relative/extension-origin URLs for
the chrome-extension:// context, and having dashboard-server.js dynamically
generate a manifest at /manifest.webmanifest with absolute
https://my.dash.board/ URLs — satisfying Chrome's same-origin requirement
for PWA installability.
Also serve extension icons at https://my.dash.board/icons/<file> with
correct bundle key mapping, and embed them in the distributable binary
via build-distributable.js.
Serve the dashboard over a local HTTPS virtual host (my.dash.board) so
Chrome treats it as a secure origin and shows the PWA install prompt.
- Add native-host/dashboard-server.js: bare-http1 static file server
backed by bare-bundle assets in distribution mode, disk fallback in dev
- Add setLocalVirtualHost() to virtual-hosts.js; type:local entries are
protected from removal and filtered out of saveState persistence
- Export setLocalVirtualHost from holesail-manager/index.js
- Start dashboard server in startup.js after proxies are ready and
register my.dash.board as a local virtual host
- Stop dashboard server in message-router.js cleanup()
- Update manifest.webmanifest: start_url, id, scope → https://my.dash.board/
- Embed all extension/dashboard/ files as bare-bundle assets in
build-distributable.js patchBundle() — no installer copy step needed
- Hide checkbox, hs:// URL, Reconnect, and Remove controls for built-in
my.dash.board row in the virtual hosts table UI
Critical fixes:
- Fix wrong registry key (com.bridgeswarm → com.holesail.browser) in
update-native-manifest-extension-id.ps1 — script was always failing on Windows
- Create missing wrong-domain.html redirect page for .host.test URLs
- Remove options_ui pointing to non-existent options.html from manifest
High-priority bug fixes:
- ssh-manager: track and kill orphaned printf FIFO writer when key auth succeeds
- ssh-manager: fix uncancelled 2000ms fallback password timer (assign to fallbackTimer,
clear in cancelPasswordWatch); fix null-check before removeAllListeners
- ssh-manager: add 30s Promise.race timeout to holesailInst.ready()
- backup-manager: fix macOS cp -R nesting bug by removing destination before copy;
add tar -tzf integrity check after archive creation
- host.js: restoreBackup now stops running tunnels before restore and re-starts them
- holesail-manager: fix stale closure bug in virtual host and service tunnel
error/close handlers (guard with v.holesail === hs check)
- dashboard.js: remove dead setText('dashTabs', ...) call referencing non-existent element
Medium improvements:
- manifest: remove unused storage and scripting permissions; restrict
web_accessible_resources match from <all_urls> to chrome-extension://*/*
- background.js: fix self-referential browser alias (globalThis.browser ?? chrome);
add 30s per-request timeout to send(); clean up dashboardTabs on tab close
- holesail-manager: gate saveStateSync stderr log behind DEBUG flag; updateSettings
now returns requiresRestart:true when proxy port changes; add backupRetention field
- host.js: pass requiresRestart through in updateSettings response
- dashboard.js: remove dead loadSettings() function; add requiresRestart warning toast;
add chrome.runtime.lastError guards in fetchState and refreshBackups;
set dynamic version from chrome.runtime.getManifest()
- dashboard.html: remove stray </button> tag; add id="sidebarVersion" for dynamic version
- install.sh/install.ps1: fetch version from RELEASE_BASE/VERSION instead of hardcoded 1.0.0
- install.ps1: add Firefox .xpi download and Firefox registry key
- update-native-manifest-extension-id.sh: add optional Firefox manifest update
- certificate-authority.js: defer RSA key generation to setImmediate to avoid blocking
startup; expose caReady promise
- host.js: await caReady before starting HTTPS proxy
Documentation:
- REMOTE-DESKTOP.md: correct RDP WebSocket protocol field names to match rdp-manager.js
(destLeft/destTop/destRight/destBottom, mouseMove/mouseButton/keyEvent/keyUnicode)
Feature additions:
- dashboard.js: add Reconnect button for service tunnels in error/closed state
- https-proxy.js: add WebSocket upgrade handler to support ws:// over *.hole.sail
- connect-proxy.js: add 10s header-read timeout to protect against idle connections
- native-host: add bare-fs as explicit dependency