@hayasaka7/haya-pet 0.1.0
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/.gitattributes +34 -0
- package/.github/workflows/release.yml +61 -0
- package/LICENSE +21 -0
- package/README.md +247 -0
- package/apps/cli/src/haya-pet.js +395 -0
- package/apps/cli/test/haya-pet.test.mjs +339 -0
- package/apps/companion/README.md +83 -0
- package/apps/companion/package.json +17 -0
- package/apps/companion/src/main/display-manager.js +71 -0
- package/apps/companion/src/main/index.js +349 -0
- package/apps/companion/src/main/lock-file.js +52 -0
- package/apps/companion/src/main/panel-placement.js +45 -0
- package/apps/companion/src/main/pet-loader.js +2 -0
- package/apps/companion/src/main/position-store.js +3 -0
- package/apps/companion/src/main/preload.cjs +13 -0
- package/apps/companion/src/main/state-file.js +2 -0
- package/apps/companion/src/main/terminal-helper-client.js +79 -0
- package/apps/companion/src/main/terminal-locator.js +44 -0
- package/apps/companion/src/main/tray-menu.js +79 -0
- package/apps/companion/src/main/window-options.js +66 -0
- package/apps/companion/src/renderer/index.html +18 -0
- package/apps/companion/src/renderer/interaction-controller.js +114 -0
- package/apps/companion/src/renderer/pet-window.js +275 -0
- package/apps/companion/src/renderer/session-bubbles.js +138 -0
- package/apps/companion/src/renderer/styles.css +225 -0
- package/apps/companion/src/renderer/task-talk-window.js +141 -0
- package/apps/companion/test/display-manager.test.mjs +48 -0
- package/apps/companion/test/interaction-controller.test.mjs +107 -0
- package/apps/companion/test/panel-placement.test.mjs +60 -0
- package/apps/companion/test/position-store.test.mjs +54 -0
- package/apps/companion/test/state-file.test.mjs +52 -0
- package/apps/companion/test/terminal-helper-client.test.mjs +68 -0
- package/apps/companion/test/terminal-locator.test.mjs +35 -0
- package/apps/companion/test/tray-menu.test.mjs +45 -0
- package/apps/companion/test/window-options.test.mjs +62 -0
- package/apps/pet-preview/index.html +42 -0
- package/apps/pet-preview/src/preview-app.js +123 -0
- package/apps/pet-preview/src/preview-state.js +70 -0
- package/apps/pet-preview/src/preview.css +125 -0
- package/apps/pet-preview/test/preview-state.test.mjs +62 -0
- package/assets/fallback-pet/README.md +16 -0
- package/assets/fallback-pet/pet.json +13 -0
- package/docs/architecture.md +144 -0
- package/docs/known-issues.md +49 -0
- package/docs/publishing.md +48 -0
- package/docs/screenshots/README.md +7 -0
- package/docs/screenshots/folder-collapsed.png +0 -0
- package/docs/screenshots/hero.png +0 -0
- package/docs/screenshots/pet-overlay.png +0 -0
- package/docs/screenshots/session-bubbles.png +0 -0
- package/docs/screenshots/tray-menu.png +0 -0
- package/docs/troubleshooting.md +36 -0
- package/native/README.md +80 -0
- package/native/linux-window-helper/README.md +29 -0
- package/native/mac-window-helper/README.md +30 -0
- package/native/win-window-helper/Program.cs +312 -0
- package/native/win-window-helper/README.md +53 -0
- package/native/win-window-helper/win-window-helper.csproj +12 -0
- package/package.json +35 -0
- package/packages/adapters/src/adapter-info.js +61 -0
- package/packages/adapters/src/capabilities.js +39 -0
- package/packages/adapters/src/heuristics.js +114 -0
- package/packages/adapters/src/output-observer.js +164 -0
- package/packages/adapters/src/routing.js +86 -0
- package/packages/adapters/test/adapter-info.test.mjs +35 -0
- package/packages/adapters/test/capabilities.test.mjs +44 -0
- package/packages/adapters/test/heuristics.test.mjs +42 -0
- package/packages/adapters/test/output-observer.test.mjs +142 -0
- package/packages/adapters/test/routing.test.mjs +93 -0
- package/packages/app-state/src/state-file.js +53 -0
- package/packages/app-state/src/state.js +80 -0
- package/packages/app-state/test/state.test.mjs +36 -0
- package/packages/cli-core/src/companion-launcher.js +69 -0
- package/packages/cli-core/src/pty-runner.js +96 -0
- package/packages/cli-core/src/run-command.js +353 -0
- package/packages/cli-core/src/strip-ansi.js +16 -0
- package/packages/cli-core/test/companion-launcher.test.mjs +98 -0
- package/packages/cli-core/test/run-command.test.mjs +177 -0
- package/packages/cli-core/test/strip-ansi.test.mjs +27 -0
- package/packages/daemon-core/src/daemon-runtime.js +49 -0
- package/packages/daemon-core/src/ipc-server.js +180 -0
- package/packages/daemon-core/src/ipc-transport.js +70 -0
- package/packages/daemon-core/src/singleton.js +46 -0
- package/packages/daemon-core/test/daemon-runtime.test.mjs +65 -0
- package/packages/daemon-core/test/ipc-server.test.mjs +70 -0
- package/packages/daemon-core/test/ipc-transport.test.mjs +72 -0
- package/packages/daemon-core/test/singleton.test.mjs +32 -0
- package/packages/pet-core/src/animation-state.js +84 -0
- package/packages/pet-core/src/animator.js +26 -0
- package/packages/pet-core/src/atlas.js +81 -0
- package/packages/pet-core/src/discovery.js +90 -0
- package/packages/pet-core/src/manifest.js +112 -0
- package/packages/pet-core/src/validation.js +43 -0
- package/packages/pet-core/test/animation-state.test.mjs +47 -0
- package/packages/pet-core/test/animator.test.mjs +31 -0
- package/packages/pet-core/test/atlas.test.mjs +81 -0
- package/packages/pet-core/test/discovery.test.mjs +93 -0
- package/packages/pet-core/test/manifest.test.mjs +93 -0
- package/packages/pet-core/test/validation.test.mjs +69 -0
- package/packages/platform-core/src/capabilities.js +49 -0
- package/packages/platform-core/src/paths.js +75 -0
- package/packages/platform-core/src/platform.js +15 -0
- package/packages/platform-core/test/platform.test.mjs +84 -0
- package/packages/protocol/src/messages.js +156 -0
- package/packages/protocol/test/messages.test.mjs +112 -0
- package/packages/session-core/src/bubble-linger.js +47 -0
- package/packages/session-core/src/bubble-view.js +79 -0
- package/packages/session-core/src/pet-state.js +56 -0
- package/packages/session-core/src/priority.js +56 -0
- package/packages/session-core/src/registry.js +144 -0
- package/packages/session-core/src/summaries.js +54 -0
- package/packages/session-core/test/bubble-linger.test.mjs +96 -0
- package/packages/session-core/test/bubble-view.test.mjs +79 -0
- package/packages/session-core/test/pet-state.test.mjs +118 -0
- package/packages/session-core/test/priority.test.mjs +53 -0
- package/packages/session-core/test/registry.test.mjs +161 -0
- package/packages/session-core/test/summaries.test.mjs +38 -0
- package/packages/task-core/src/approvals.js +91 -0
- package/packages/task-core/src/controls.js +61 -0
- package/packages/task-core/src/replies.js +80 -0
- package/packages/task-core/src/task-events.js +101 -0
- package/packages/task-core/src/task-status.js +93 -0
- package/packages/task-core/src/task-store.js +74 -0
- package/packages/task-core/test/approvals.test.mjs +61 -0
- package/packages/task-core/test/controls.test.mjs +61 -0
- package/packages/task-core/test/replies.test.mjs +51 -0
- package/packages/task-core/test/task-events.test.mjs +67 -0
- package/packages/task-core/test/task-status.test.mjs +49 -0
- package/packages/task-core/test/task-store.test.mjs +65 -0
- package/test/harness.mjs +22 -0
- package/test/run-tests.mjs +47 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
How Haya Pet is put together. For installing and using it, see the
|
|
4
|
+
[README](../README.md); this doc is for contributors and the curious.
|
|
5
|
+
|
|
6
|
+
## Pipeline
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
AI terminal clients
|
|
10
|
+
→ client adapters (normalize behavior into a common event model)
|
|
11
|
+
→ haya-petd daemon (sessions, priority, pet state, IPC)
|
|
12
|
+
→ shared pet runtime (assets, animation, interaction)
|
|
13
|
+
→ desktop overlay (global pet + session bubbles)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
You launch any AI CLI through the `haya-pet` wrapper. The wrapper registers a
|
|
17
|
+
session and reports lifecycle/activity events to the daemon over local IPC (a
|
|
18
|
+
named pipe on Windows, a unix socket elsewhere). The first `haya-pet run`
|
|
19
|
+
**auto-starts the daemon/overlay**, so users only ever type `haya-pet run …`.
|
|
20
|
+
|
|
21
|
+
| Component | Responsibility |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `haya-pet` (CLI) | Wrapper: launches clients, registers sessions, reports events, auto-starts the companion. |
|
|
24
|
+
| `haya-petd` (companion) | Global daemon + overlay: owns sessions, pet state, windows, IPC. |
|
|
25
|
+
| adapters | Translate client-specific behavior into the common state model. |
|
|
26
|
+
| pet-core | Loads pet assets, computes frames, drives animation state. |
|
|
27
|
+
| session-core | Tracks sessions, priority, summaries, bubble view models, linger. |
|
|
28
|
+
| task-core | Task status, events, approvals, replies, control gating (reply/approval UI is parked). |
|
|
29
|
+
| platform-core | Per-OS paths, capabilities, and fallback tiers. |
|
|
30
|
+
|
|
31
|
+
## Normalized state model
|
|
32
|
+
|
|
33
|
+
Every client maps to a shared state vocabulary that drives the pet animation and
|
|
34
|
+
the bubble status icons:
|
|
35
|
+
|
|
36
|
+
`idle`, `thinking`, `running_tool`, `editing_files`, `waiting_user`,
|
|
37
|
+
`waiting_approval`, `reviewing`, `compacting`, `failed`, `success`, `stale`,
|
|
38
|
+
`exited`.
|
|
39
|
+
|
|
40
|
+
Bubbles collapse these into four status kinds: **working** (spinner), **done**
|
|
41
|
+
(check), **attention** (yellow), **failed** (red cross).
|
|
42
|
+
|
|
43
|
+
## Adapter support tiers
|
|
44
|
+
|
|
45
|
+
The daemon never bakes in client-specific logic; adapters provide as much fidelity
|
|
46
|
+
as each client allows:
|
|
47
|
+
|
|
48
|
+
| Tier | Source | Fidelity |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| L1 | Process wrapper (lifecycle only) | session exists / exit code |
|
|
51
|
+
| L2 | PTY output observation (`--observe`, default) | activity-based working/idle |
|
|
52
|
+
| L3 | Client logs / state files | client-specific (future) |
|
|
53
|
+
| L4 | Official plugin/hooks | richest (future) |
|
|
54
|
+
|
|
55
|
+
L2 is **activity-based**: any visible output → *working*; a short quiet window →
|
|
56
|
+
*idle*; success/failure come from the real exit code, never from scraping output
|
|
57
|
+
text. Keyword heuristics exist but are opt-in (unreliable on rich TUIs). See
|
|
58
|
+
[known-issues.md](known-issues.md) for the current L2/PTY tradeoffs.
|
|
59
|
+
|
|
60
|
+
## Overlay model
|
|
61
|
+
|
|
62
|
+
The overlay is a transparent, always-on-top window spanning the work area, kept
|
|
63
|
+
click-through except over the pet and bubble chips (via `setIgnoreMouseEvents`
|
|
64
|
+
with mouse-move forwarding). The pet is positioned inside the window and dragged
|
|
65
|
+
via CSS; the bubble panel is placed on whichever side of the pet has room so it
|
|
66
|
+
stays fully on-screen. The pet currently lives on a single display's work area.
|
|
67
|
+
|
|
68
|
+
## Distribution & runtime dependencies
|
|
69
|
+
|
|
70
|
+
- `electron` is a **runtime dependency** (not just a dev tool), because
|
|
71
|
+
`haya-pet run` launches the overlay by spawning `electron <companion>`.
|
|
72
|
+
- `node-pty` is **optional**: live observation (L2) uses it, and degrades to L1
|
|
73
|
+
lifecycle tracking when it's absent.
|
|
74
|
+
- Auto-start can be disabled with `HAYA_PET_NO_AUTOSTART=1`; `haya-pet start` /
|
|
75
|
+
`haya-pet stop` control the overlay explicitly.
|
|
76
|
+
|
|
77
|
+
See [publishing.md](publishing.md) for the npm release process.
|
|
78
|
+
|
|
79
|
+
## Project structure
|
|
80
|
+
|
|
81
|
+
```text
|
|
82
|
+
packages/
|
|
83
|
+
protocol/ IPC message types + validation
|
|
84
|
+
pet-core/ atlas, manifest, validation, animator, animation-state
|
|
85
|
+
session-core/ registry, priority, summaries, bubble views, linger, pet-state
|
|
86
|
+
task-core/ task status, events, store, approvals, replies, controls
|
|
87
|
+
adapters/ client info, heuristics, capabilities, output observer, routing
|
|
88
|
+
daemon-core/ IPC server/transport, runtime bridge, singleton
|
|
89
|
+
platform-core/ platform, paths, capabilities
|
|
90
|
+
apps/
|
|
91
|
+
cli/ haya-pet entrypoint + parser (run / start / stop / pets)
|
|
92
|
+
companion/ Electron overlay app (main + renderer)
|
|
93
|
+
pet-preview/ static preview scaffold
|
|
94
|
+
native/
|
|
95
|
+
win-window-helper/ Windows terminal-window helper (.NET, implemented)
|
|
96
|
+
mac-window-helper/ macOS helper (contract documented)
|
|
97
|
+
linux-window-helper/ Linux X11/Wayland helper (contract documented)
|
|
98
|
+
assets/
|
|
99
|
+
fallback-pet/ bundled fallback pet manifest
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
There are no per-package `package.json` files — packages import each other by
|
|
103
|
+
relative path, which is also why the whole tree ships as one npm package.
|
|
104
|
+
|
|
105
|
+
## Platform support
|
|
106
|
+
|
|
107
|
+
| Feature | Windows | macOS | Linux X11 | Linux Wayland |
|
|
108
|
+
|---|---|---|---|---|
|
|
109
|
+
| Protocol / session core | ✅ | ✅ | ✅ | ✅ |
|
|
110
|
+
| Generic CLI wrapper | ✅ | ✅ | ✅ | ✅ |
|
|
111
|
+
| Local daemon IPC | named pipe | unix socket | unix socket | unix socket |
|
|
112
|
+
| Transparent overlay | ✅ | ✅ | ✅ | best-effort |
|
|
113
|
+
| Terminal attachment | ✅ helper | 🔜 | 🔜 | fallback |
|
|
114
|
+
|
|
115
|
+
See [cross-os-qa.md](cross-os-qa.md) for the full test matrix.
|
|
116
|
+
|
|
117
|
+
## Native window helpers
|
|
118
|
+
|
|
119
|
+
Optional per-OS helpers locate terminal windows so bubbles can attach near them.
|
|
120
|
+
|
|
121
|
+
```powershell
|
|
122
|
+
# Windows (.NET SDK 10, net10.0-windows):
|
|
123
|
+
cd native\win-window-helper
|
|
124
|
+
dotnet build -c Release
|
|
125
|
+
# -> bin/Release/net10.0-windows/haya-pet-win-window-helper.exe
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
macOS (Swift/AppKit) and Linux (X11/Wayland) helpers have documented contracts
|
|
129
|
+
but are not yet implemented.
|
|
130
|
+
|
|
131
|
+
## Status & roadmap
|
|
132
|
+
|
|
133
|
+
Implemented and tested: shared core, CLI wrapper (run/start/stop/pets),
|
|
134
|
+
auto-start, daemon IPC + shutdown, adapters, PTY-based live observation,
|
|
135
|
+
Codex-style session bubbles, the Electron overlay, and the Windows terminal
|
|
136
|
+
helper. In progress:
|
|
137
|
+
|
|
138
|
+
- Bidirectional IPC so the daemon routes replies/approvals back to the wrapper
|
|
139
|
+
(re-enabling the parked reply/approval UI).
|
|
140
|
+
- macOS (Swift/AppKit) and Linux X11 terminal helpers.
|
|
141
|
+
- Faithful PTY passthrough (see [known-issues.md](known-issues.md)).
|
|
142
|
+
- Production overlay/IPC validation across all platforms.
|
|
143
|
+
|
|
144
|
+
See [`../PROGRESS.md`](../PROGRESS.md) for the detailed log.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Known Issues (deferred)
|
|
2
|
+
|
|
3
|
+
Issues found in live use that are **recorded for later** — not yet fixed. The
|
|
4
|
+
decision on *how* to fix is pending.
|
|
5
|
+
|
|
6
|
+
## 1. Terminal scrolling breaks when running a CLI through `haya-pet run` (observe/PTY mode)
|
|
7
|
+
|
|
8
|
+
- **Symptom:** While a CLI is running under `haya-pet run` (default `--observe`), the
|
|
9
|
+
terminal window can no longer scroll normally.
|
|
10
|
+
- **Trigger:** Only in observe (PTY) mode. The plain `--no-observe` path
|
|
11
|
+
(`stdio: "inherit"`) does not have this problem.
|
|
12
|
+
- **Diagnosis:** Observe mode runs the CLI inside a `node-pty`/ConPTY pseudo-terminal
|
|
13
|
+
with a fixed `cols × rows` and tees its output to our `stdout`
|
|
14
|
+
(`packages/cli-core/src/pty-runner.js`). Full-screen TUIs (Claude Code, Codex)
|
|
15
|
+
render into that fixed grid, so the outer terminal's scrollback only ever sees
|
|
16
|
+
redraws of the grid rather than a growing transcript — there is effectively
|
|
17
|
+
nothing meaningful to scroll. On Windows there is an extra layer: shims are run
|
|
18
|
+
as `cmd /d /s /c "<shim> ..."` *inside* the PTY, so `cmd.exe` is the PTY's
|
|
19
|
+
foreground process and the TUI is its child.
|
|
20
|
+
- **Notes for a future fix:** Tools like `script`/`asciinema` interpose a PTY
|
|
21
|
+
without breaking the terminal, so a faithful passthrough is achievable. Avenues:
|
|
22
|
+
resolve the shim and spawn the real executable directly in the PTY (drop the
|
|
23
|
+
`cmd /c` layer); verify `cols/rows` always match the host; revisit whether
|
|
24
|
+
observe should be the default for interactive TUIs vs. native passthrough.
|
|
25
|
+
|
|
26
|
+
## 2. Backspace deletes a whole word instead of one character (observe/PTY mode)
|
|
27
|
+
|
|
28
|
+
- **Symptom:** While a CLI is running under `haya-pet run`, pressing Backspace
|
|
29
|
+
deletes an entire word rather than a single character.
|
|
30
|
+
- **Trigger:** Only in observe (PTY) mode. Native (`--no-observe`) is unaffected.
|
|
31
|
+
- **Diagnosis:** stdin is put in raw mode and forwarded byte-for-byte into the PTY
|
|
32
|
+
(`pty-runner.js` `forwardInput` → `child.write(chunk.toString("utf8"))`). The
|
|
33
|
+
whole-word deletion points to a key-encoding/line-discipline mismatch between the
|
|
34
|
+
host terminal (Windows Terminal/conhost) and the nested ConPTY (and possibly the
|
|
35
|
+
intermediate `cmd /c`) — e.g. Backspace `0x7f`/`0x08` being interpreted by the
|
|
36
|
+
inner app as a word-delete (Ctrl+W `0x17` / Alt+Backspace `ESC 0x7f`), or input
|
|
37
|
+
bytes being re-segmented across `data` events.
|
|
38
|
+
- **Notes for a future fix:** Forward stdin as raw bytes without a UTF-8 round-trip;
|
|
39
|
+
audit the exact bytes the host sends for Backspace vs. what the inner app receives
|
|
40
|
+
(a small PTY echo harness); consider removing the `cmd /c` layer; re-evaluate
|
|
41
|
+
raw-mode handling. Hard to fully verify without interactive testing.
|
|
42
|
+
|
|
43
|
+
## Shared root cause & the open decision
|
|
44
|
+
|
|
45
|
+
Both issues stem from observe mode interposing a pseudo-terminal on an interactive
|
|
46
|
+
session. The plain wrapper path avoids them entirely but cannot report fine-grained
|
|
47
|
+
"thinking / running tools" status. The open product decision: **native terminal by
|
|
48
|
+
default (perfect fidelity, coarser status) vs. keep PTY observation default and
|
|
49
|
+
invest in faithful passthrough.** Deferred until the maintainer decides.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Publishing
|
|
2
|
+
|
|
3
|
+
How Haya Pet is released to npm. Most users never need this — see the
|
|
4
|
+
[README](../README.md) to install and use it.
|
|
5
|
+
|
|
6
|
+
## Release flow
|
|
7
|
+
|
|
8
|
+
Releases are automated by [`.github/workflows/release.yml`](../.github/workflows/release.yml):
|
|
9
|
+
pushing a `v*` tag triggers a workflow that installs, runs the tests, checks the
|
|
10
|
+
tag matches `package.json`, and publishes to npm.
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm version patch # bumps package.json + creates tag vX.Y.Z
|
|
14
|
+
git push --follow-tags # pushes the tag → triggers the release workflow
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The workflow installs with `ELECTRON_SKIP_BINARY_DOWNLOAD=1` (the ~150 MB binary
|
|
18
|
+
isn't needed to test or publish) and publishes with
|
|
19
|
+
`npm publish --provenance --access public` using the `NPM_TOKEN` secret.
|
|
20
|
+
|
|
21
|
+
## One-time setup
|
|
22
|
+
|
|
23
|
+
1. **`NPM_TOKEN` secret** — create an npm *automation* (or granular publish) token
|
|
24
|
+
at npmjs.com and add it under GitHub → repo Settings → Secrets and variables →
|
|
25
|
+
Actions → `NPM_TOKEN`.
|
|
26
|
+
2. **Package name** — confirm the name in `package.json` is available
|
|
27
|
+
(`npm view <name>`); rename or use a scope (`@you/haya-pet`) if taken. The
|
|
28
|
+
workflow already passes `--access public` for scoped packages.
|
|
29
|
+
3. **`private` removed** — `npm publish` refuses private packages; the root
|
|
30
|
+
`package.json` must not have `"private": true` (already removed).
|
|
31
|
+
4. **Provenance / public repo** — `--provenance` requires a public repo and the
|
|
32
|
+
`id-token: write` permission (set in the workflow). Drop `--provenance` if the
|
|
33
|
+
repo is private.
|
|
34
|
+
|
|
35
|
+
## Notes
|
|
36
|
+
|
|
37
|
+
- **Local registry mirror.** If your local npm points at a mirror (e.g.
|
|
38
|
+
`registry.npmmirror.com`), don't `npm publish` locally — the workflow targets
|
|
39
|
+
`registry.npmjs.org` explicitly, which is what you want.
|
|
40
|
+
- **Lockfile sync.** After changing dependencies in `package.json`, refresh the
|
|
41
|
+
lockfile (`npm install --package-lock-only`) and commit it, or CI's `npm ci`
|
|
42
|
+
will fail on the mismatch.
|
|
43
|
+
- **Tarball contents.** The package ships the whole tree (`apps/` + `packages/`)
|
|
44
|
+
because modules import each other by relative path. Test files are currently
|
|
45
|
+
included; add a `"files"` allowlist to `package.json` to trim the tarball to
|
|
46
|
+
runtime code only.
|
|
47
|
+
- **Runtime deps.** `electron` is a dependency (the CLI launches it); `node-pty`
|
|
48
|
+
is optional (native build; live observation degrades gracefully without it).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
Place screenshot PNGs referenced by the root README here (~800px wide):
|
|
2
|
+
|
|
3
|
+
- `hero.png` — wide shot: the pet on the desktop with a couple of session bubbles
|
|
4
|
+
- `pet-overlay.png` — the pet reacting to the highest-priority session
|
|
5
|
+
- `session-bubbles.png` — bubbles expanded, showing per-session status icons
|
|
6
|
+
- `folder-collapsed.png` — bubbles folded away beside the pet
|
|
7
|
+
- `tray-menu.png` — the tray menu (show/hide, pets, reset position, Quit)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Troubleshooting
|
|
2
|
+
|
|
3
|
+
Quick fixes for common issues. See also [known-issues.md](known-issues.md) for
|
|
4
|
+
deferred problems with known root causes.
|
|
5
|
+
|
|
6
|
+
| Symptom | Fix |
|
|
7
|
+
|---|---|
|
|
8
|
+
| `haya-pet: command not found` | Install globally (`npm i -g …`), or in a source checkout run `npm link` in the repo root, or call the file directly: `node <repo>/apps/cli/src/haya-pet.js`. |
|
|
9
|
+
| Running a CLI starts the pet but not the command | Fixed — update to the latest version. (Was caused by the auto-start poll exiting early.) |
|
|
10
|
+
| Pet doesn't react to a session | Launch the CLI via `haya-pet run …`. If the overlay didn't auto-start, run `haya-pet start`, or check `HAYA_PET_NO_AUTOSTART` isn't set. |
|
|
11
|
+
| Pet shows a blue placeholder box | No spritesheet found — add a pet (see the README); behaviour is otherwise correct. |
|
|
12
|
+
| Pet is off-screen / can't find it | Tray icon → **Reset Position**. |
|
|
13
|
+
| Can't exit the pet | `haya-pet stop`, or right-click the tray icon → **Quit**. |
|
|
14
|
+
| `haya-pet pets` shows "No pets found" | Add a pet folder with **both** `pet.json` and a spritesheet to a search path. |
|
|
15
|
+
| Terminal scroll / backspace odd while a CLI runs under `haya-pet run` | Known PTY-observation tradeoff — see [known-issues.md](known-issues.md). Workaround: `haya-pet run --no-observe …`. |
|
|
16
|
+
| `ENOENT … electron\path.txt` | Electron's install extraction was interrupted — see below. |
|
|
17
|
+
|
|
18
|
+
## Fixing a broken Electron install
|
|
19
|
+
|
|
20
|
+
If launching the overlay fails with `ENOENT … node_modules\electron\path.txt`,
|
|
21
|
+
the Electron binary downloaded but extraction left `dist/` empty. The cached zip
|
|
22
|
+
is fine, so re-extract it without re-downloading (PowerShell, from the repo root):
|
|
23
|
+
|
|
24
|
+
```powershell
|
|
25
|
+
$cache = Get-ChildItem "$env:LOCALAPPDATA\electron\Cache" -Recurse -Filter "electron-*.zip" |
|
|
26
|
+
Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
|
27
|
+
$dist = "node_modules\electron\dist"
|
|
28
|
+
Remove-Item -Recurse -Force $dist -ErrorAction SilentlyContinue
|
|
29
|
+
New-Item -ItemType Directory $dist | Out-Null
|
|
30
|
+
Expand-Archive -Path $cache.FullName -DestinationPath $dist -Force
|
|
31
|
+
Set-Content "node_modules\electron\path.txt" "electron.exe" -NoNewline
|
|
32
|
+
node_modules\.bin\electron --version # should print the version
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If `electron.exe` is missing even after a clean `Expand-Archive`, your antivirus
|
|
36
|
+
likely quarantined it — allow `node_modules\electron\dist\electron.exe` and retry.
|
package/native/README.md
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Native Window Helpers
|
|
2
|
+
|
|
3
|
+
Terminal-window discovery is platform-specific and is isolated behind small,
|
|
4
|
+
optional native helper processes. The JavaScript runtime never links native
|
|
5
|
+
code directly; it spawns a helper and talks to it over a line-delimited JSON
|
|
6
|
+
protocol on stdin/stdout. This keeps the daemon portable and lets the helper be
|
|
7
|
+
written in the most appropriate language per OS (C#/Win32, Swift/AppKit, C/Xlib).
|
|
8
|
+
|
|
9
|
+
The `apps/companion/src/main/terminal-locator.js` facade decides *which* helper
|
|
10
|
+
strategy applies per platform (`win32-window-helper`, `macos-accessibility-helper`,
|
|
11
|
+
`x11-window-helper`, or `manual-fallback`). When the strategy is implemented, the
|
|
12
|
+
main process spawns the matching helper and uses this contract.
|
|
13
|
+
|
|
14
|
+
## Transport
|
|
15
|
+
|
|
16
|
+
- One JSON object per line (`\n`-delimited), UTF-8, on both stdin and stdout.
|
|
17
|
+
- The helper is long-lived: it reads requests until stdin closes.
|
|
18
|
+
- The helper must never write anything but protocol JSON to stdout. Diagnostics
|
|
19
|
+
go to stderr.
|
|
20
|
+
|
|
21
|
+
## Requests
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{ "id": "req_1", "op": "capabilities" }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{ "id": "req_2", "op": "locate", "pid": 12345, "terminalPid": 5678 }
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Field | Meaning |
|
|
32
|
+
|---|---|
|
|
33
|
+
| `id` | Opaque correlation id echoed back in the response. |
|
|
34
|
+
| `op` | `"capabilities"` or `"locate"`. |
|
|
35
|
+
| `pid` | AI client process id (walk its parent tree to the terminal). |
|
|
36
|
+
| `terminalPid` | Optional known terminal pid hint. |
|
|
37
|
+
|
|
38
|
+
## Responses
|
|
39
|
+
|
|
40
|
+
Capabilities:
|
|
41
|
+
|
|
42
|
+
```json
|
|
43
|
+
{ "id": "req_1", "ok": true, "capabilities": { "locate": true, "follow": false, "permission": "granted" } }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Locate (found):
|
|
47
|
+
|
|
48
|
+
```json
|
|
49
|
+
{
|
|
50
|
+
"id": "req_2",
|
|
51
|
+
"ok": true,
|
|
52
|
+
"window": {
|
|
53
|
+
"x": 100,
|
|
54
|
+
"y": 200,
|
|
55
|
+
"width": 1200,
|
|
56
|
+
"height": 760,
|
|
57
|
+
"displayId": "primary",
|
|
58
|
+
"title": "pwsh — project",
|
|
59
|
+
"confidence": 0.8
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Locate (not found / unsupported / permission denied):
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{ "id": "req_2", "ok": false, "error": "not_found" }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`error` is one of: `not_found`, `unsupported`, `permission_denied`, `invalid_request`.
|
|
71
|
+
|
|
72
|
+
## Rules
|
|
73
|
+
|
|
74
|
+
- Coordinates are in OS virtual-screen pixels; the runtime converts to the pet's
|
|
75
|
+
display/DPI space using `display-manager.js`.
|
|
76
|
+
- A helper that cannot resolve a window must return `ok:false`, never guess.
|
|
77
|
+
- `permission` in capabilities lets the UI explain why attachment is unavailable
|
|
78
|
+
(e.g. macOS Accessibility not granted) and fall back to manual/cluster bubbles.
|
|
79
|
+
- Helpers are best-effort. The runtime always supports manual bubble positioning
|
|
80
|
+
when a helper reports `unsupported` or `permission_denied`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Linux Window Helper
|
|
2
|
+
|
|
3
|
+
Strategy ids: `x11-window-helper` (X11, best-effort) and `manual-fallback` (Wayland).
|
|
4
|
+
|
|
5
|
+
Implements the shared helper protocol in [`../README.md`](../README.md).
|
|
6
|
+
|
|
7
|
+
## Responsibility
|
|
8
|
+
|
|
9
|
+
- On X11: discover terminal windows through Xlib (`_NET_WM_PID`, `XGetWindowProperty`)
|
|
10
|
+
or a `wmctrl`/`xdotool`-style approach, match the tracked process tree, and
|
|
11
|
+
return window bounds.
|
|
12
|
+
- On Wayland: report limited capability instead of assuming global window
|
|
13
|
+
positioning works.
|
|
14
|
+
|
|
15
|
+
## Implementation notes
|
|
16
|
+
|
|
17
|
+
- Suggested language: C with Xlib/XCB, or a thin wrapper over `wmctrl`/`xdotool`.
|
|
18
|
+
- X11: match `_NET_WM_PID` against the AI client's parent terminal pid; read
|
|
19
|
+
geometry via `XGetGeometry` + `XTranslateCoordinates` for absolute coordinates.
|
|
20
|
+
- Wayland: most compositors block global window enumeration/positioning. The
|
|
21
|
+
helper should answer `capabilities` with `{ "locate": false }` and return
|
|
22
|
+
`{ "ok": false, "error": "unsupported" }` for `locate`, so the runtime uses
|
|
23
|
+
global pet + cluster/manual bubbles.
|
|
24
|
+
|
|
25
|
+
## Protocol mapping
|
|
26
|
+
|
|
27
|
+
- X11 `op: "capabilities"` → `{ "locate": true, "follow": false, "permission": "granted" }`.
|
|
28
|
+
- Wayland `op: "capabilities"` → `{ "locate": false, "follow": false, "permission": "granted" }`.
|
|
29
|
+
- `op: "locate"` → `window` rect on X11 when found, otherwise `not_found` / `unsupported`.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# macOS Window Helper
|
|
2
|
+
|
|
3
|
+
Strategy id: `macos-accessibility-helper` (best-effort).
|
|
4
|
+
|
|
5
|
+
Implements the shared helper protocol in [`../README.md`](../README.md).
|
|
6
|
+
|
|
7
|
+
## Responsibility
|
|
8
|
+
|
|
9
|
+
- Locate Terminal.app, iTerm2, VS Code, or other terminal windows for tracked
|
|
10
|
+
process trees.
|
|
11
|
+
- Use the Accessibility API (`AXUIElement`) or `CGWindowListCopyWindowInfo`
|
|
12
|
+
where permission is available.
|
|
13
|
+
- Return window bounds and permission status for bubble attachment.
|
|
14
|
+
|
|
15
|
+
## Implementation notes
|
|
16
|
+
|
|
17
|
+
- Suggested language: Swift with AppKit/ApplicationServices.
|
|
18
|
+
- Accessibility requires the user to grant permission in System Settings →
|
|
19
|
+
Privacy & Security → Accessibility. When not granted, return
|
|
20
|
+
`{ "ok": false, "error": "permission_denied" }` and report
|
|
21
|
+
`"permission": "denied"` from `capabilities` so the UI can prompt the user.
|
|
22
|
+
- Handle Retina scale: report points and include the backing scale so the
|
|
23
|
+
runtime can map to device pixels.
|
|
24
|
+
- Spaces/full-screen windows may be undiscoverable; return `not_found` rather
|
|
25
|
+
than guessing.
|
|
26
|
+
|
|
27
|
+
## Protocol mapping
|
|
28
|
+
|
|
29
|
+
- `op: "capabilities"` → `{ "locate": true, "follow": false, "permission": "granted" | "denied" }`.
|
|
30
|
+
- `op: "locate"` → `window` rect on success, or `permission_denied` / `not_found`.
|