@bitefoundry/retrieviewer 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DESKTOP-PLATFORMS.md +70 -0
- package/INSTALLING.md +28 -6
- package/README.md +33 -5
- package/RELEASING.md +15 -4
- package/WINDOWS-COMPANION.md +113 -0
- package/integrations/desktop/platform.mjs +27 -0
- package/integrations/linux-overlay/README.md +83 -0
- package/integrations/linux-overlay/overlay.py +1094 -0
- package/integrations/macos-overlay/README.md +83 -0
- package/integrations/macos-overlay/overlay.jxa +637 -0
- package/integrations/windows-overlay/Overlay.cs +259 -0
- package/integrations/windows-overlay/desktop.mjs +119 -0
- package/integrations/windows-overlay/protocol.mjs +39 -0
- package/integrations/windows-overlay/worker.mjs +66 -0
- package/package.json +15 -3
- package/retrieviewer-cli.mjs +25 -5
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Native desktop adapters — 0.0.3
|
|
2
|
+
|
|
3
|
+
Version0.0.3 includes Windows, Linux X11 and experimental macOS adapters. Windows
|
|
4
|
+
and the AlmaLinux8 X11 baseline have live verification; macOS has no runtime verification.
|
|
5
|
+
Installation takes two steps: `npm install -g @bitefoundry/retrieviewer`,
|
|
6
|
+
then `retrieviewer desktop`. No app patch, wrapper, shell profile or auto-start entry.
|
|
7
|
+
|
|
8
|
+
## Design and status
|
|
9
|
+
|
|
10
|
+
| Platform | Adapter | Current verification boundary |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| Windows10/11 | .NET Framework/Win32 layered window | Live verified; shared-adapter regression checks passed on this host |
|
|
13
|
+
| macOS | Built-in osascript/JXA AppKit, no Python/Xcode/browser runtime | Experimental; no macOS runtime available on this Windows host |
|
|
14
|
+
| Linux X11 | Python3.6+ stdlib ctypes + X11/Xrender/Xext | AlmaLinux8 GLIBC2.28/Python3.6.8/Node22.23.4 live checks passed on owned Xvfb + Openbox + xcompmgr |
|
|
15
|
+
| Linux native Wayland | No arbitrary-window tracking adapter | Refused, including sessions exposing an Xwayland DISPLAY; no insecure compositor workaround |
|
|
16
|
+
|
|
17
|
+
Linux needs a running Xorg/X11 desktop with an ARGB visual, SHAPE input extension
|
|
18
|
+
and a compositing window manager. A headless/server-only AlmaLinux installation
|
|
19
|
+
cannot display desktop windows. System Python3.6+ is used; AlmaLinux8's
|
|
20
|
+
`/usr/libexec/platform-python` is a fallback. No pip packages, GTK, Qt, Electron,
|
|
21
|
+
native npm addons or on-machine C/C++ compilation are required on Linux. Missing
|
|
22
|
+
capabilities cause a clear error rather than silently installing packages or
|
|
23
|
+
changing a login/session/privacy setting. The source must not require a newer
|
|
24
|
+
GLIBC just because the development workstation has one.
|
|
25
|
+
|
|
26
|
+
AlmaLinux8 users should use an officially maintained Node22 build compatible
|
|
27
|
+
with their GLIBC2.28 system. The package's Node>=20 range is not a promise that
|
|
28
|
+
every future upstream Node binary will run on an old OS. The baseline test uses
|
|
29
|
+
official Node22.23.4 linux-x64, SHA256
|
|
30
|
+
`1805bcd35e6815559bd2eb97db438d3fdb0eb3a5e6a977b7c1badca76337e9ce`.
|
|
31
|
+
|
|
32
|
+
## Low-resource behavior
|
|
33
|
+
|
|
34
|
+
Linux/macOS worker loops default to15fps, Windows retains30fps. Real elapsed time
|
|
35
|
+
drives the existing fixed-step animation: fewer drawn frames do not deliberately
|
|
36
|
+
speed the dog up. There is at most one frame in flight. Only the cropped, nonblank
|
|
37
|
+
Braille rectangle crosses the pipe and is painted. Hidden/inactive/minimized
|
|
38
|
+
time is paused and never replayed on reveal. Native adapters should default to
|
|
39
|
+
coarser cells/bounded grids on large displays instead of rendering a4K framebuffer.
|
|
40
|
+
This is a design target, not a claim of zero CPU use or a measured memory minimum.
|
|
41
|
+
|
|
42
|
+
In the owned1280×800 Alma8 test the Node engine RSS was about179MiB, plus the
|
|
43
|
+
Python helper. This is not a minimum-memory requirement or proof of4K performance.
|
|
44
|
+
|
|
45
|
+
All adapters reuse the same Q5 art and behavior engine. POSIX control sockets use
|
|
46
|
+
short `/tmp/retrieviewer-overlay-<uid>-<uuid>.sock` addresses with0600 permissions,
|
|
47
|
+
an independently random token in the0600 session record, and conservative cleanup.
|
|
48
|
+
Windows named pipes remain compatible with the previous launcher. No token is
|
|
49
|
+
printed in status or sent over a network. Same-user hostile software remains
|
|
50
|
+
outside the security boundary. Stop/remove must not kill or modify the target app.
|
|
51
|
+
|
|
52
|
+
## Evidence
|
|
53
|
+
|
|
54
|
+
Keep actual checks, failures, skips and the tested OS separate. Static macOS source
|
|
55
|
+
tests cannot establish AppKit/JXA behavior or privacy permissions. An Ubuntu test
|
|
56
|
+
with a newer libc is not AlmaLinux8/GLIBC2.28 certification. A fake window manager
|
|
57
|
+
is not proof of composited visual quality. Test containers may install their own
|
|
58
|
+
QA tools, but product launch never installs OS packages or changes the user's OS.
|
|
59
|
+
|
|
60
|
+
Recorded Linux checks: real ARGB painting, empty input shape, moved target geometry,
|
|
61
|
+
stale-frame discard, hide on unmap, target disappearance, foreground retention,
|
|
62
|
+
actual Node-to-Python worker painting, accepted ball interaction,0600 UNIX socket,
|
|
63
|
+
rejected wrong token, clean worker/helper exit, and remove lifecycle. This covers
|
|
64
|
+
an isolated desktop, not every GNOME/KDE theme, compositor or physical monitor.
|
|
65
|
+
Evidence: `dist/alma8-qa/posix-worker.json` and source QA script output.
|
|
66
|
+
|
|
67
|
+
- [Node build platform requirements](https://github.com/nodejs/node/blob/v22.23.4/BUILDING.md)
|
|
68
|
+
- [X11 Shape protocol](https://xorg.freedesktop.org/archive/X11R7.7/doc/xextproto/shape.html)
|
|
69
|
+
- [Wayland client surface isolation](https://wayland.pages.freedesktop.org/wayland.freedesktop.org/docs/book/Protocol.html)
|
|
70
|
+
- [Apple NSWindow](https://developer.apple.com/documentation/appkit/nswindow)
|
package/INSTALLING.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Install Retrieviewer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Desktop setup (Node20+; [OS requirements and verification](DESKTOP-PLATFORMS.md)):
|
|
4
|
+
|
|
5
|
+
1. `npm install -g @bitefoundry/retrieviewer`
|
|
6
|
+
2. `retrieviewer desktop` — select the app window in the picker.
|
|
7
|
+
|
|
8
|
+
No agent configuration is needed for this separate transparent companion.
|
|
9
|
+
Windows and AlmaLinux8/GLIBC2.28 X11 have live test evidence. macOS support is
|
|
10
|
+
experimental and not runtime verified; native Wayland is unsupported. Linux needs
|
|
11
|
+
system Python3.6+, X11/Xrender/Xext and a compositor; Windows needs the .NET
|
|
12
|
+
Framework4 compiler. See [Windows controls and removal](WINDOWS-COMPANION.md).
|
|
13
|
+
|
|
14
|
+
## Optional native OpenCode integration
|
|
15
|
+
|
|
16
|
+
0.0.3 also includes an installer CLI and a native OpenCode TUI adapter. It does **not** claim
|
|
4
17
|
that every MCP client can display animated UI. Native OpenCode rendering uses its
|
|
5
18
|
official TUI plugin slot, not another terminal, a wrapper, or a modified binary.
|
|
6
19
|
Other agent IDs are discoverable but refused until an adapter is implemented.
|
|
@@ -12,7 +25,7 @@ agent are required. Source code is MIT; bundled puppy artwork is CC BY-SA 4.0.
|
|
|
12
25
|
Keep the included ATTRIBUTION.md and asset license when redistributing artwork.
|
|
13
26
|
|
|
14
27
|
```sh
|
|
15
|
-
npm install -g @bitefoundry/retrieviewer
|
|
28
|
+
npm install -g @bitefoundry/retrieviewer
|
|
16
29
|
retrieviewer enable
|
|
17
30
|
```
|
|
18
31
|
|
|
@@ -31,9 +44,7 @@ version is **not automatically certified**. Existing project configuration can
|
|
|
31
44
|
override global settings; doctor checks registration, not arbitrary host precedence.
|
|
32
45
|
Do not put API keys in Retrieviewer settings. No credentials are needed by the pet.
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
`npm install -g @bitefoundry/retrieviewer@0.0.1`. Do not run that registry command
|
|
36
|
-
before publication. The package also exports `./tui` for npm-aware OpenCode plugin
|
|
47
|
+
The package also exports `./tui` for npm-aware OpenCode plugin
|
|
37
48
|
loaders; package-name discovery has not yet been live-tested against npm.
|
|
38
49
|
The verified installer continues using its local directory URL, not that new path.
|
|
39
50
|
|
|
@@ -54,6 +65,17 @@ the new package. No automatic global install is done by the package itself.
|
|
|
54
65
|
|
|
55
66
|
## Commands
|
|
56
67
|
|
|
68
|
+
For the separate native overlay (Windows since0.0.2; Linux X11 and experimental macOS since0.0.3),
|
|
69
|
+
see [desktop platforms](DESKTOP-PLATFORMS.md). It does not register a Codex plugin
|
|
70
|
+
or change the way an agent is launched:
|
|
71
|
+
|
|
72
|
+
```powershell
|
|
73
|
+
retrieviewer desktop
|
|
74
|
+
retrieviewer desktop-status --json
|
|
75
|
+
retrieviewer desktop-stop
|
|
76
|
+
retrieviewer desktop-remove --yes
|
|
77
|
+
```
|
|
78
|
+
|
|
57
79
|
```sh
|
|
58
80
|
retrieviewer agents --json
|
|
59
81
|
retrieviewer status --agent opencode
|
package/README.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Retrieviewer
|
|
2
2
|
|
|
3
|
-
An autonomous, fluffy Braille retriever that lives
|
|
3
|
+
An autonomous, fluffy Braille retriever that lives above your app window or in a TUI pane.
|
|
4
4
|
Give it a ball or a treat; otherwise it wanders and plays on its own. By BiteFoundry.
|
|
5
5
|
|
|
6
|
-
**Version 0.0.
|
|
6
|
+
**Version 0.0.3.** Source code is MIT; puppy artwork is CC BY-SA 4.0, including
|
|
7
7
|
commercial use and adaptations under its attribution/ShareAlike conditions.
|
|
8
8
|
See [licensing](./LICENSE), [artwork terms](./ASSETS-LICENSE.md),
|
|
9
9
|
[credits](./ATTRIBUTION.md) and [brand notice](./TRADEMARKS.md).
|
|
@@ -11,11 +11,39 @@ The complete package is not MIT-only.
|
|
|
11
11
|
|
|
12
12
|
## Install
|
|
13
13
|
|
|
14
|
-
Node.js >=20
|
|
14
|
+
Node.js >=20 is required. Windows10/11 x64 uses the Windows .NET Framework4
|
|
15
|
+
compiler (automatic helper build on first launch). Linux needs X11, a compositor,
|
|
16
|
+
system Python3.6+ and X11/Xrender/Xext; AlmaLinux8/GLIBC2.28 has been tested.
|
|
17
|
+
macOS uses built-in osascript/AppKit and is **experimental, not runtime verified**.
|
|
18
|
+
Native Wayland is not supported. See [platform requirements](./DESKTOP-PLATFORMS.md).
|
|
19
|
+
|
|
20
|
+
1. Install:
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
npm install -g @bitefoundry/retrieviewer
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
2. Run and choose the app window you want your puppy to live on:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
retrieviewer desktop
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
That's it. Use your app normally. Ball/treat controls sit above the selected
|
|
33
|
+
window; the pet lets ordinary clicks through. No Codex patch, wrapper, MCP setup,
|
|
34
|
+
administrator access, or automatic startup registration. It follows a whole window,
|
|
35
|
+
not individual tabs, and hides when you switch away. It is a separate transparent
|
|
36
|
+
native window, **not a widget injected into another app**. macOS is experimental;
|
|
37
|
+
exclusive fullscreen apps and privileged/security surfaces are not certified.
|
|
38
|
+
|
|
39
|
+
Exit from the tray icon or `retrieviewer desktop-stop`. To remove the companion's
|
|
40
|
+
own cache, run `retrieviewer desktop-remove --yes`; then
|
|
41
|
+
`npm uninstall -g @bitefoundry/retrieviewer` removes the package. See
|
|
42
|
+
[platform support](./DESKTOP-PLATFORMS.md) and [Windows controls and removal](./WINDOWS-COMPANION.md).
|
|
43
|
+
|
|
44
|
+
## Optional: native OpenCode pane
|
|
15
45
|
|
|
16
46
|
```sh
|
|
17
|
-
npm install -g @bitefoundry/retrieviewer@0.0.1
|
|
18
|
-
retrieviewer enable --agent opencode --dry-run
|
|
19
47
|
retrieviewer enable --agent opencode --yes
|
|
20
48
|
opencode
|
|
21
49
|
```
|
package/RELEASING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Retrieviewer 0.0.
|
|
1
|
+
# Retrieviewer 0.0.3 release process
|
|
2
2
|
|
|
3
|
-
Target: `@bitefoundry/retrieviewer@0.0.
|
|
3
|
+
Target: `@bitefoundry/retrieviewer@0.0.3`, public npm registry, `latest` tag.
|
|
4
4
|
The npm organization `bitefoundry` uses the free public-packages plan; account
|
|
5
5
|
`shinick` owns the organization.
|
|
6
6
|
|
|
@@ -12,6 +12,12 @@ artwork draft is superseded. ATTRIBUTION.md retains the photographic references
|
|
|
12
12
|
and original license links. ASSET-PROVENANCE.md records the bounded review and
|
|
13
13
|
remaining limits; this is not comprehensive legal clearance.
|
|
14
14
|
|
|
15
|
+
The owner explicitly authorized publishing0.0.3 with the cross-platform companion
|
|
16
|
+
and the two-step npm install/desktop launch guide. Windows and the AlmaLinux8
|
|
17
|
+
GLIBC2.28 X11 baseline have live test evidence; macOS ships as experimental and
|
|
18
|
+
not runtime verified. Native Wayland is unsupported. No new art license or Codex
|
|
19
|
+
modification is part of this release. Preserve all earlier registry artifacts.
|
|
20
|
+
|
|
15
21
|
`release-policy.json` has four independent approval gates and the CC artwork
|
|
16
22
|
license identifier. The guard still refuses false/missing approvals, private
|
|
17
23
|
packages, missing attribution/notices, install scripts and known leaked paths.
|
|
@@ -29,7 +35,7 @@ npm publish --dry-run --access public --registry=https://registry.npmjs.org/
|
|
|
29
35
|
The package test packs the exact candidate, installs it in a fresh offline
|
|
30
36
|
consumer, byte-compares all installed files and checks exports, frames,
|
|
31
37
|
interactions, lifecycle, examples, JSONL and isolated installer settings.
|
|
32
|
-
Its report is `dist/package-check.json`; it does not publish or edit live
|
|
38
|
+
Its report is in a fresh `dist/package-check-*/package-check.json`; it does not publish or edit live
|
|
33
39
|
agent configuration. Keep the final tarball hash and file inventory.
|
|
34
40
|
|
|
35
41
|
The product workspace is not a Git repository. No public source repository,
|
|
@@ -37,7 +43,7 @@ Actions pipeline or npm trusted publisher is implied by this npm release.
|
|
|
37
43
|
Do not upload this experimental workspace wholesale: original photos, source
|
|
38
44
|
image sheets, workers, QA receipts, credentials and local settings stay local.
|
|
39
45
|
|
|
40
|
-
##
|
|
46
|
+
## Publish the tested tarball
|
|
41
47
|
|
|
42
48
|
Confirm `npm whoami` is the intended account. Publish only the tested candidate
|
|
43
49
|
with explicit public access; complete any npm browser/2FA verification through
|
|
@@ -58,4 +64,9 @@ discovery alone is not live-host certification. Other agent-native renderers
|
|
|
58
64
|
remain unimplemented. MCP alone cannot inject a pet into arbitrary agent UIs.
|
|
59
65
|
See INSTALLING.md for support and removal.
|
|
60
66
|
|
|
67
|
+
The separate transparent companion uses platform-native windows plus the same pet
|
|
68
|
+
engine. Test real installed copies with isolated state and owned diagnostic windows;
|
|
69
|
+
do not stop the user's live companion merely to run QA. See DESKTOP-PLATFORMS.md
|
|
70
|
+
for verified checks, experimental macOS status and unsupported environments.
|
|
71
|
+
|
|
61
72
|
Historical research notes remain local and are not current support promises.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Windows companion — 0.0.2
|
|
2
|
+
|
|
3
|
+
This is a separate transparent desktop window, not a Codex plugin or a terminal
|
|
4
|
+
wrapper. Version0.0.2 includes it; version0.0.1 does not. Setup is two steps:
|
|
5
|
+
|
|
6
|
+
1. `npm install -g @bitefoundry/retrieviewer`
|
|
7
|
+
2. `retrieviewer desktop` — choose the app window in the picker.
|
|
8
|
+
|
|
9
|
+
Choose a supported ordinary Windows app window (including a terminal containing
|
|
10
|
+
Codex). Then use your app normally, without a
|
|
11
|
+
wrapper, shell alias, patched binary, changed credentials, or agent configuration.
|
|
12
|
+
The helper uses native Windows/.NET Framework facilities and the existing Node
|
|
13
|
+
pet engine. No Electron, Chromium, downloaded helper binary or new npm dependency.
|
|
14
|
+
Windows10/11 x64 with Node20+ and the .NET Framework4 compiler is required. Other
|
|
15
|
+
desktop platforms and exclusive fullscreen/security surfaces are not certified.
|
|
16
|
+
Launch reports
|
|
17
|
+
that the picker is ready, **not** that the user has selected a window or visually
|
|
18
|
+
approved the pet.
|
|
19
|
+
|
|
20
|
+
## Interaction and window scope
|
|
21
|
+
|
|
22
|
+
- The original Q5 Braille artwork/behavior engine is reused without new sprites.
|
|
23
|
+
- The pet is click-through and non-activating. It does not read keyboard input.
|
|
24
|
+
- A small separate, non-activating control strip offers ball, treat, choose window,
|
|
25
|
+
pause and exit. These buttons consume their own clicks, not terminal typing.
|
|
26
|
+
- Ball/treat use the existing engine interactions, including busy/cooldown rules.
|
|
27
|
+
Ball currently uses its existing preset destination, **not free mouse aiming**.
|
|
28
|
+
- The overlay follows the selected window's client rectangle. It hides and stops
|
|
29
|
+
simulation when another app is foreground, the target is minimized, or paused.
|
|
30
|
+
The control strip remains available while paused in the selected window.
|
|
31
|
+
- It binds a whole top-level window, **not a terminal tab/pane**. Switching tabs
|
|
32
|
+
inside that window does not automatically rebind or identify the running agent.
|
|
33
|
+
- Selection is per launch. There is no process scanning to infer Codex sessions,
|
|
34
|
+
screen scraping/OCR, chat capture, global keyboard hook or input injection.
|
|
35
|
+
The picker locally reads window titles/process names; tracking reads window
|
|
36
|
+
geometry, foreground state, visibility and owning process ID.
|
|
37
|
+
- No automatic startup, background scheduled task, registry entry or MCP is added.
|
|
38
|
+
Exit stops both the painter and engine. If either process closes, its counterpart
|
|
39
|
+
exits too. Losing the target hides the pet; tray selection can attach another.
|
|
40
|
+
|
|
41
|
+
## Stop, remove, and recover
|
|
42
|
+
|
|
43
|
+
```powershell
|
|
44
|
+
retrieviewer desktop-status --json
|
|
45
|
+
retrieviewer desktop-stop
|
|
46
|
+
retrieviewer desktop-clean --yes
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
One-command companion removal (stop, wait for exit, remove only its cache):
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
retrieviewer desktop-remove --yes
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The tray icon also provides window selection, hide/resume and exit. `desktop-stop`
|
|
56
|
+
asks the companion to exit through an authenticated local named pipe; it never
|
|
57
|
+
kills a PID from a stale file. The worker may terminate only its own stuck child
|
|
58
|
+
painter after a graceful timeout. Cache cleanup refuses a live/unreachable worker,
|
|
59
|
+
symlinks/junctions and unrecognized session records. It removes only recognized
|
|
60
|
+
helper cache filenames; unrelated files and agent/pet settings remain untouched.
|
|
61
|
+
|
|
62
|
+
Own files are under `~/.config/retrieviewer/desktop` (or RETRIEVIEWER_HOME/desktop):
|
|
63
|
+
one hash-named compiled helper and a transient local session capability record.
|
|
64
|
+
The token is not printed by status and is never sent over a network. Same-user
|
|
65
|
+
local software is not treated as an adversarial security boundary. No screenshot,
|
|
66
|
+
terminal content or window title is persisted by this companion.
|
|
67
|
+
|
|
68
|
+
For a globally installed copy, stop/remove the companion before
|
|
69
|
+
`npm uninstall -g @bitefoundry/retrieviewer`. Other native OpenCode registrations,
|
|
70
|
+
if any, must first be disconnected with the existing explicit disconnect command.
|
|
71
|
+
This companion does not change or remove a pre-existing Codex `/pets` pack.
|
|
72
|
+
|
|
73
|
+
## Rendering and bounded work
|
|
74
|
+
|
|
75
|
+
Native pixels are dots decoded from the engine's existing Braille cells, on an
|
|
76
|
+
alpha-transparent bitmap. Every frame starts clear, avoiding previous-frame paw
|
|
77
|
+
trails. Only the nonblank bounding rectangle crosses IPC and is painted; the
|
|
78
|
+
native window does not allocate a full-screen transparent bitmap. A request/ack
|
|
79
|
+
bridge permits only one frame in flight. Viewport revisions discard frames from
|
|
80
|
+
an old size/position; discarded frames are acknowledged to avoid deadlock. Hidden
|
|
81
|
+
time is not replayed when the pet becomes visible. The engine targets30fps, but
|
|
82
|
+
the actual frame rate depends on CPU, window resolution and Windows scheduling.
|
|
83
|
+
|
|
84
|
+
## Search-first decision and evidence
|
|
85
|
+
|
|
86
|
+
Reused `createPet` and its side-effect-free host API. A small native Win32 painter
|
|
87
|
+
was selected for Windows instead of adding an Electron runtime or a PTY wrapper.
|
|
88
|
+
The former adds another browser runtime; the latter changes how Codex is launched
|
|
89
|
+
and was explicitly rejected. This is not a claim of cross-platform support or a
|
|
90
|
+
benchmarked memory advantage; measurements belong to the local validation.
|
|
91
|
+
|
|
92
|
+
- [Layered windows and mouse passthrough](https://learn.microsoft.com/en-us/windows/win32/winmsg/window-features#layered-windows)
|
|
93
|
+
- [UpdateLayeredWindow](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-updatelayeredwindow)
|
|
94
|
+
- [No-activate extended window style](https://learn.microsoft.com/en-us/windows/win32/winmsg/extended-window-styles)
|
|
95
|
+
- [SetWindowPos without activation](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setwindowpos)
|
|
96
|
+
- [Electron alternative](https://www.electronjs.org/docs/latest/tutorial/custom-window-interactions)
|
|
97
|
+
|
|
98
|
+
`node --test retrieviewer-desktop.test.mjs` covers transport/cropping/backpressure,
|
|
99
|
+
hidden-time resets, CLI isolation, authenticated control transport and conservative
|
|
100
|
+
cleanup. Native validation must additionally test layered window rendering, focus,
|
|
101
|
+
geometry, minimize/restore, controls and lifecycle on an actual Windows desktop.
|
|
102
|
+
Do not equate style checks or a rendered PNG with end-user visual approval.
|
|
103
|
+
|
|
104
|
+
Local validation on2026-10-23:281 automated tests passed, real packaged offline
|
|
105
|
+
consumer passed, and the real native worker painted frames with the actual pet
|
|
106
|
+
engine. The native ball button reached the engine and was accepted; an incorrect
|
|
107
|
+
control token was rejected. Owned off-screen native-window checks passed position
|
|
108
|
+
tracking, minimize/restore, passthrough/no-activate styles and foreground retention.
|
|
109
|
+
The worker and painter both exited. Node RSS was about157MiB in that small-window
|
|
110
|
+
check (not total app memory or a4K performance claim). A Windows GUI startup bug
|
|
111
|
+
was fixed by building a GUI-subsystem helper and not applying SW_HIDE to it; the
|
|
112
|
+
real user picker was verified in Windows' visible main-window list. User visual
|
|
113
|
+
approval after selecting a terminal remains separate.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Dependency-free platform selection. Importing performs no probing or I/O.
|
|
2
|
+
import {posix} from 'node:path';
|
|
3
|
+
export function desktopPlatform({platform=process.platform,env=process.env,glibc}={}){
|
|
4
|
+
if(platform==='win32')return {id:'windows-overlay',fps:30,helper:'windows',experimental:false};
|
|
5
|
+
if(platform==='darwin')return {id:'macos-overlay',fps:15,helper:'macos',experimental:true};
|
|
6
|
+
if(platform==='linux'){
|
|
7
|
+
if(env.XDG_SESSION_TYPE?.trim().toLowerCase()==='wayland'||env.WAYLAND_DISPLAY)throw Error('Native Wayland cannot safely track arbitrary app windows. Log in to an Xorg/X11 session; no compositor or privacy settings will be changed.');
|
|
8
|
+
if(!env.DISPLAY)throw Error('Linux desktop requires an X11 DISPLAY and a compositing window manager. Headless/SSH sessions are not a desktop.');
|
|
9
|
+
if(glibc!==undefined){const parts=String(glibc).split('.').map(Number);if(!/^\d+\.\d+(?:\.\d+)?$/.test(String(glibc))||parts[0]<2||(parts[0]===2&&parts[1]<28))throw Error('Linux desktop requires GLIBC2.28 or later (AlmaLinux8 baseline).');}
|
|
10
|
+
return {id:'linux-x11-overlay',fps:15,helper:'linux',experimental:true};
|
|
11
|
+
}
|
|
12
|
+
throw Error('Desktop companion supports Windows, macOS and Linux X11 only');
|
|
13
|
+
}
|
|
14
|
+
export function controlAddress({platform=process.platform,uuid,uid=process.getuid?.()??0}={}){
|
|
15
|
+
if(!/^[a-f0-9-]{36}$/.test(uuid))throw Error('Invalid desktop control UUID');
|
|
16
|
+
if(platform==='win32')return '\\\\.\\pipe\\retrieviewer-overlay-'+uuid;
|
|
17
|
+
if(!Number.isSafeInteger(uid)||uid<0)throw Error('Invalid desktop user ID');
|
|
18
|
+
// Short enough for macOS's104-byte sockaddr_un, regardless of HOME/TMPDIR length.
|
|
19
|
+
return posix.join('/tmp',`retrieviewer-overlay-${uid}-${uuid}.sock`);
|
|
20
|
+
}
|
|
21
|
+
export function validControlAddress(value){return typeof value==='string'&&(/^\\\\\.\\pipe\\retrieviewer-overlay-[a-f0-9-]{36}$/.test(value)||/^\/tmp\/retrieviewer-overlay-\d+-[a-f0-9-]{36}\.sock$/.test(value));}
|
|
22
|
+
export function parseHelperSpec(argv){
|
|
23
|
+
if(argv[0]!=='--helper-spec')return {command:argv[0],args:argv[1]==='--ipc-test'?['--ipc-test']:[],mode:'windows-overlay',fps:30};
|
|
24
|
+
const value=JSON.parse(argv[1]);
|
|
25
|
+
if(!value||typeof value.command!=='string'||!value.command||value.command.includes('\0')||!Array.isArray(value.args)||value.args.some(a=>typeof a!=='string'||a.includes('\0'))||!['windows-overlay','macos-overlay','linux-x11-overlay'].includes(value.mode)||!Number.isInteger(value.fps)||value.fps<5||value.fps>30)throw Error('Invalid desktop helper descriptor');
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Linux X11 companion painter (implementation-ready, not release-certified)
|
|
2
|
+
|
|
3
|
+
`overlay.py` is the Linux counterpart of `../windows-overlay/Overlay.cs`: a
|
|
4
|
+
native transparent painter driven over the same NDJSON stdin/stdout bridge by the
|
|
5
|
+
Node pet engine. It draws only the Braille frames it receives; it adds no art.
|
|
6
|
+
|
|
7
|
+
## Why Python + ctypes
|
|
8
|
+
|
|
9
|
+
- Python 3.6+ **standard library only**. `ctypes` binds the X client libraries
|
|
10
|
+
the desktop already ships: `libX11.so.6`, `libXrender.so.1`, `libXext.so.6`.
|
|
11
|
+
- No compiler, PyPI package, GTK/Qt/gi/Tk, Electron or npm native addon, so there
|
|
12
|
+
is no GLIBC/Node ABI coupling. Target baseline: AlmaLinux 8 (GLIBC 2.28,
|
|
13
|
+
platform Python 3.6) on old hardware.
|
|
14
|
+
- Struct layouts and constants were checked against the official X.org headers
|
|
15
|
+
(libX11 1.8.13, libXrender 0.9.12, libXext 1.3.4, xorgproto 2025.1) with a
|
|
16
|
+
compiled `offsetof`/`sizeof` probe on x86_64. 32-bit layouts were not
|
|
17
|
+
compiled; every field uses `c_long`/`c_ulong`/pointers so they follow the C ABI.
|
|
18
|
+
|
|
19
|
+
## Requirements and refusals (fail closed, one JSON `error` line, exit 2)
|
|
20
|
+
|
|
21
|
+
| Condition | Result |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `WAYLAND_DISPLAY` set or `XDG_SESSION_TYPE=wayland` (even with `DISPLAY`/XWayland) | Refused: log in to an Xorg session. Wayland cannot safely follow/stack over another app. |
|
|
24
|
+
| `DISPLAY` unset / display cannot be opened | Refused with the display name. |
|
|
25
|
+
| No SHAPE ≥ 1.1 (input shapes), no RENDER, no XRender ARGB32 32-bit visual | Refused. |
|
|
26
|
+
| No compositing manager (`_NET_WM_CM_Sn` unowned) | Refused instead of painting an opaque black box. |
|
|
27
|
+
| WM without EWMH `_NET_CLIENT_LIST` / `_NET_ACTIVE_WINDOW` | Refused. |
|
|
28
|
+
| Missing X client library | Refused; it never installs packages. |
|
|
29
|
+
|
|
30
|
+
## Bridge (same as Windows)
|
|
31
|
+
|
|
32
|
+
stdin: `frame{revision,x,y,columns,rows,text}`, `loaded`, `interaction`, `error`, `quit`.
|
|
33
|
+
stdout: `ready{pickerVisible}`, `picker{visible}`,
|
|
34
|
+
`viewport{revision,visible,selected,columns,rows,cellWidth,cellHeight=2*cellWidth}`,
|
|
35
|
+
`ack{painted}`, `interact{kind:ball|treat}`, `pause{paused}`, `quit`.
|
|
36
|
+
|
|
37
|
+
- One outstanding frame; discarded, hidden and stale-revision frames are still ACKed.
|
|
38
|
+
- Only U+2800..U+28FF cells; ≤ 125000 cells per frame. Default cell is 16 px and the
|
|
39
|
+
viewport grid is capped at 20000 cells (`--cell 6|8|10|12|16` to change the cell).
|
|
40
|
+
- Only the cropped bounding box is rasterized; the pet window is resized to it and
|
|
41
|
+
fully overwritten, and is unmapped on every viewport change, so no stale trails.
|
|
42
|
+
- stdin EOF quits; every owned window, GC and colormap is released and the display
|
|
43
|
+
connection closed. The single-instance lock is an abstract Unix socket (no file).
|
|
44
|
+
|
|
45
|
+
## Window behavior
|
|
46
|
+
|
|
47
|
+
- Explicit picker lists EWMH client windows (title and `/proc/PID/comm` only,
|
|
48
|
+
terminals first). Titles are drawn ASCII-only (`?` for other characters).
|
|
49
|
+
The picker sets `WM_HINTS.input=False` so the WM should not move keyboard focus.
|
|
50
|
+
- Tracking is read-only polling (~30 Hz) of the target's attributes, root-relative
|
|
51
|
+
position, `_NET_WM_STATE_HIDDEN`, `_NET_WM_PID` and `_NET_ACTIVE_WINDOW`. The pet
|
|
52
|
+
shows only while the target is the active window, viewable, not minimized and at
|
|
53
|
+
least 160×120. A vanished target (BadWindow is trapped) or reused PID hides it.
|
|
54
|
+
- Pet: override-redirect ARGB32 window with an **empty ShapeInput region**, so all
|
|
55
|
+
pointer input passes through; no keyboard selection, grabs or hotkeys.
|
|
56
|
+
- Controls: a separate override-redirect strip (Ball, Treat, Window, Pause, Quit)
|
|
57
|
+
consumes only its own clicks and is never focused.
|
|
58
|
+
- Target windows and global focus are never modified. No capture, injection,
|
|
59
|
+
network, root access or Wayland compositor changes.
|
|
60
|
+
|
|
61
|
+
## Commands
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
python3 overlay.py # bridge mode (spawned by the Node worker)
|
|
65
|
+
python3 overlay.py --ipc-test # bridge mode with an owned off-screen stand-in target
|
|
66
|
+
python3 overlay.py --check-json # environment diagnostics, creates no windows
|
|
67
|
+
python3 overlay.py --self-test :99 # owned windows on an explicitly named isolated display (e.g. Xvfb)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`--self-test` refuses an implicit display; it does not require a compositor and
|
|
71
|
+
checks painting, input-shape emptiness, geometry following, stale-frame discard,
|
|
72
|
+
hide on unmap, target loss, focus preservation and teardown on owned windows only.
|
|
73
|
+
|
|
74
|
+
## Known limits
|
|
75
|
+
|
|
76
|
+
- Parent verification after the worker report: AlmaLinux8/GLIBC2.28, Python3.6.8,
|
|
77
|
+
Node22.23.4, owned Xvfb + Openbox + xcompmgr passed native painting, empty input
|
|
78
|
+
shape, focus/geometry/hide/stale-frame checks and real Node worker ball/exit
|
|
79
|
+
lifecycle. This is not certification of every physical desktop/compositor.
|
|
80
|
+
- Compositors may draw a shadow around override-redirect windows; the pet window
|
|
81
|
+
declares `_NET_WM_WINDOW_TYPE_DND`, which most compositors leave unshadowed.
|
|
82
|
+
- The overlay is raised every 250 ms while visible because a WM restacks the active
|
|
83
|
+
target above override-redirect windows when it is clicked.
|