fix(desktop): explain unavailable Windows ARM64 window context
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { type EnumeratedWindow, enumerationFailureNote, pickWindowBelow, resolveOutsideAsar } from './window-below'
|
||||
import {
|
||||
type EnumeratedWindow,
|
||||
enumerationFailureNote,
|
||||
getWindowsFailureReason,
|
||||
pickWindowBelow,
|
||||
resolveOutsideAsar
|
||||
} from './window-below'
|
||||
|
||||
const win = (pid: number, x = 0, y = 0, width = 800, height = 600, app = `app-${pid}`): EnumeratedWindow => ({
|
||||
app,
|
||||
@@ -146,6 +152,32 @@ describe('enumerationFailureNote', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('getWindowsFailureReason', () => {
|
||||
it('explains the native binding gap on Windows ARM64 without discarding the failure', () => {
|
||||
for (const detail of [
|
||||
'module missing',
|
||||
'binding failed to load',
|
||||
'the window enumerator returned no window list'
|
||||
]) {
|
||||
const reason = getWindowsFailureReason(detail, 'win32', 'arm64')
|
||||
|
||||
expect(reason).toContain(detail)
|
||||
expect(reason).toMatch(/win32-arm64/)
|
||||
expect(reason).toMatch(/native binding/)
|
||||
expect(reason).toMatch(/x64/)
|
||||
expect(enumerationFailureNote('win32', {}, reason)).toContain(reason)
|
||||
|
||||
for (const [platform, arch] of [
|
||||
['win32', 'x64'],
|
||||
['darwin', 'arm64'],
|
||||
['linux', 'arm64']
|
||||
]) {
|
||||
expect(getWindowsFailureReason(detail, platform, arch)).toBe(detail)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('resolveOutsideAsar', () => {
|
||||
// The helper binary get-windows execs cannot run from inside the archive
|
||||
// (execFile on a path through app.asar fails ENOTDIR), so the import must
|
||||
|
||||
@@ -145,6 +145,19 @@ export interface EnumerationFailure {
|
||||
export const enumerationFailed = <T>(result: EnumerationFailure | T): result is EnumerationFailure =>
|
||||
typeof result === 'object' && result !== null && 'reason' in result
|
||||
|
||||
// Keep the native provider's failure detail shared by the tool and HUD log.
|
||||
export function getWindowsFailureReason(detail: string, platform: string, arch: string): string {
|
||||
if (platform === 'win32' && arch === 'arm64') {
|
||||
return (
|
||||
`${detail}. Window context requires a working win32-arm64 native binding; ` +
|
||||
'get-windows 9.3.0 does not ship one. Use the x64 desktop build under Windows emulation, ' +
|
||||
'or a build with a matching native binding. This affects both read_window_below and HUD window context.'
|
||||
)
|
||||
}
|
||||
|
||||
return detail
|
||||
}
|
||||
|
||||
const describeError = (error: unknown): string =>
|
||||
error instanceof Error ? error.message : String(error ?? 'unknown error')
|
||||
|
||||
@@ -284,7 +297,11 @@ export async function enumerateWindowsFrontToBack(
|
||||
selfPid: number,
|
||||
titlesAvailable: boolean
|
||||
): Promise<EnumeratedWindow[] | EnumerationFailure> {
|
||||
return (await readHyprlandWindows(selfPid)) ?? (await enumerateViaGetWindows(titlesAvailable))
|
||||
const result = (await readHyprlandWindows(selfPid)) ?? (await enumerateViaGetWindows(titlesAvailable))
|
||||
|
||||
return enumerationFailed(result)
|
||||
? { reason: getWindowsFailureReason(result.reason, process.platform, process.arch) }
|
||||
: result
|
||||
}
|
||||
|
||||
export async function readWindowBelow(
|
||||
|
||||
@@ -539,6 +539,19 @@ The remote gateway host is configured per [profile](./profiles.md), so each prof
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
### Window context unavailable on Windows ARM64
|
||||
|
||||
The ARM64 desktop build's `get-windows` 9.3.0 dependency does not ship a
|
||||
`win32-arm64` native binding. Without a working binding, `read_window_below`
|
||||
and HUD window context cannot enumerate other apps' windows. The error and
|
||||
HUD log include this limitation alongside the underlying failure reason.
|
||||
|
||||
Use the x64 desktop build under Windows emulation, or a custom build with a
|
||||
matching native binding. Changing the agent backend or granting macOS screen
|
||||
permissions cannot fix a missing Windows binding; enumeration runs on the
|
||||
computer hosting the desktop app. This diagnostic does not add native ARM64
|
||||
window enumeration support.
|
||||
|
||||
- **Sign-in fails with 401 / "Invalid credentials"** — the username or password doesn't match the backend's `HERMES_DASHBOARD_BASIC_AUTH_USERNAME` / `HERMES_DASHBOARD_BASIC_AUTH_PASSWORD`. The backend returns the same generic error for an unknown user and a wrong password (no enumeration oracle), so double-check both. Confirm the gate is on with `curl -s http://<host>:9119/api/status | jq '.auth_required, .auth_providers'` — it should report `true` and include `"basic"`.
|
||||
- **No "Sign in" button — it asks for a session token instead** — the backend's username/password provider isn't active. `/api/status` won't list `"basic"` in `auth_providers`. Make sure both the username and a password (or password hash) are set in `~/.hermes/.env` and that the dashboard process actually loaded them.
|
||||
- **Signed out on every restart** — set `HERMES_DASHBOARD_BASIC_AUTH_SECRET` to a stable value. Without it the token-signing key is regenerated per boot, invalidating all sessions.
|
||||
|
||||
Reference in New Issue
Block a user