@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.
Files changed (131) hide show
  1. package/.gitattributes +34 -0
  2. package/.github/workflows/release.yml +61 -0
  3. package/LICENSE +21 -0
  4. package/README.md +247 -0
  5. package/apps/cli/src/haya-pet.js +395 -0
  6. package/apps/cli/test/haya-pet.test.mjs +339 -0
  7. package/apps/companion/README.md +83 -0
  8. package/apps/companion/package.json +17 -0
  9. package/apps/companion/src/main/display-manager.js +71 -0
  10. package/apps/companion/src/main/index.js +349 -0
  11. package/apps/companion/src/main/lock-file.js +52 -0
  12. package/apps/companion/src/main/panel-placement.js +45 -0
  13. package/apps/companion/src/main/pet-loader.js +2 -0
  14. package/apps/companion/src/main/position-store.js +3 -0
  15. package/apps/companion/src/main/preload.cjs +13 -0
  16. package/apps/companion/src/main/state-file.js +2 -0
  17. package/apps/companion/src/main/terminal-helper-client.js +79 -0
  18. package/apps/companion/src/main/terminal-locator.js +44 -0
  19. package/apps/companion/src/main/tray-menu.js +79 -0
  20. package/apps/companion/src/main/window-options.js +66 -0
  21. package/apps/companion/src/renderer/index.html +18 -0
  22. package/apps/companion/src/renderer/interaction-controller.js +114 -0
  23. package/apps/companion/src/renderer/pet-window.js +275 -0
  24. package/apps/companion/src/renderer/session-bubbles.js +138 -0
  25. package/apps/companion/src/renderer/styles.css +225 -0
  26. package/apps/companion/src/renderer/task-talk-window.js +141 -0
  27. package/apps/companion/test/display-manager.test.mjs +48 -0
  28. package/apps/companion/test/interaction-controller.test.mjs +107 -0
  29. package/apps/companion/test/panel-placement.test.mjs +60 -0
  30. package/apps/companion/test/position-store.test.mjs +54 -0
  31. package/apps/companion/test/state-file.test.mjs +52 -0
  32. package/apps/companion/test/terminal-helper-client.test.mjs +68 -0
  33. package/apps/companion/test/terminal-locator.test.mjs +35 -0
  34. package/apps/companion/test/tray-menu.test.mjs +45 -0
  35. package/apps/companion/test/window-options.test.mjs +62 -0
  36. package/apps/pet-preview/index.html +42 -0
  37. package/apps/pet-preview/src/preview-app.js +123 -0
  38. package/apps/pet-preview/src/preview-state.js +70 -0
  39. package/apps/pet-preview/src/preview.css +125 -0
  40. package/apps/pet-preview/test/preview-state.test.mjs +62 -0
  41. package/assets/fallback-pet/README.md +16 -0
  42. package/assets/fallback-pet/pet.json +13 -0
  43. package/docs/architecture.md +144 -0
  44. package/docs/known-issues.md +49 -0
  45. package/docs/publishing.md +48 -0
  46. package/docs/screenshots/README.md +7 -0
  47. package/docs/screenshots/folder-collapsed.png +0 -0
  48. package/docs/screenshots/hero.png +0 -0
  49. package/docs/screenshots/pet-overlay.png +0 -0
  50. package/docs/screenshots/session-bubbles.png +0 -0
  51. package/docs/screenshots/tray-menu.png +0 -0
  52. package/docs/troubleshooting.md +36 -0
  53. package/native/README.md +80 -0
  54. package/native/linux-window-helper/README.md +29 -0
  55. package/native/mac-window-helper/README.md +30 -0
  56. package/native/win-window-helper/Program.cs +312 -0
  57. package/native/win-window-helper/README.md +53 -0
  58. package/native/win-window-helper/win-window-helper.csproj +12 -0
  59. package/package.json +35 -0
  60. package/packages/adapters/src/adapter-info.js +61 -0
  61. package/packages/adapters/src/capabilities.js +39 -0
  62. package/packages/adapters/src/heuristics.js +114 -0
  63. package/packages/adapters/src/output-observer.js +164 -0
  64. package/packages/adapters/src/routing.js +86 -0
  65. package/packages/adapters/test/adapter-info.test.mjs +35 -0
  66. package/packages/adapters/test/capabilities.test.mjs +44 -0
  67. package/packages/adapters/test/heuristics.test.mjs +42 -0
  68. package/packages/adapters/test/output-observer.test.mjs +142 -0
  69. package/packages/adapters/test/routing.test.mjs +93 -0
  70. package/packages/app-state/src/state-file.js +53 -0
  71. package/packages/app-state/src/state.js +80 -0
  72. package/packages/app-state/test/state.test.mjs +36 -0
  73. package/packages/cli-core/src/companion-launcher.js +69 -0
  74. package/packages/cli-core/src/pty-runner.js +96 -0
  75. package/packages/cli-core/src/run-command.js +353 -0
  76. package/packages/cli-core/src/strip-ansi.js +16 -0
  77. package/packages/cli-core/test/companion-launcher.test.mjs +98 -0
  78. package/packages/cli-core/test/run-command.test.mjs +177 -0
  79. package/packages/cli-core/test/strip-ansi.test.mjs +27 -0
  80. package/packages/daemon-core/src/daemon-runtime.js +49 -0
  81. package/packages/daemon-core/src/ipc-server.js +180 -0
  82. package/packages/daemon-core/src/ipc-transport.js +70 -0
  83. package/packages/daemon-core/src/singleton.js +46 -0
  84. package/packages/daemon-core/test/daemon-runtime.test.mjs +65 -0
  85. package/packages/daemon-core/test/ipc-server.test.mjs +70 -0
  86. package/packages/daemon-core/test/ipc-transport.test.mjs +72 -0
  87. package/packages/daemon-core/test/singleton.test.mjs +32 -0
  88. package/packages/pet-core/src/animation-state.js +84 -0
  89. package/packages/pet-core/src/animator.js +26 -0
  90. package/packages/pet-core/src/atlas.js +81 -0
  91. package/packages/pet-core/src/discovery.js +90 -0
  92. package/packages/pet-core/src/manifest.js +112 -0
  93. package/packages/pet-core/src/validation.js +43 -0
  94. package/packages/pet-core/test/animation-state.test.mjs +47 -0
  95. package/packages/pet-core/test/animator.test.mjs +31 -0
  96. package/packages/pet-core/test/atlas.test.mjs +81 -0
  97. package/packages/pet-core/test/discovery.test.mjs +93 -0
  98. package/packages/pet-core/test/manifest.test.mjs +93 -0
  99. package/packages/pet-core/test/validation.test.mjs +69 -0
  100. package/packages/platform-core/src/capabilities.js +49 -0
  101. package/packages/platform-core/src/paths.js +75 -0
  102. package/packages/platform-core/src/platform.js +15 -0
  103. package/packages/platform-core/test/platform.test.mjs +84 -0
  104. package/packages/protocol/src/messages.js +156 -0
  105. package/packages/protocol/test/messages.test.mjs +112 -0
  106. package/packages/session-core/src/bubble-linger.js +47 -0
  107. package/packages/session-core/src/bubble-view.js +79 -0
  108. package/packages/session-core/src/pet-state.js +56 -0
  109. package/packages/session-core/src/priority.js +56 -0
  110. package/packages/session-core/src/registry.js +144 -0
  111. package/packages/session-core/src/summaries.js +54 -0
  112. package/packages/session-core/test/bubble-linger.test.mjs +96 -0
  113. package/packages/session-core/test/bubble-view.test.mjs +79 -0
  114. package/packages/session-core/test/pet-state.test.mjs +118 -0
  115. package/packages/session-core/test/priority.test.mjs +53 -0
  116. package/packages/session-core/test/registry.test.mjs +161 -0
  117. package/packages/session-core/test/summaries.test.mjs +38 -0
  118. package/packages/task-core/src/approvals.js +91 -0
  119. package/packages/task-core/src/controls.js +61 -0
  120. package/packages/task-core/src/replies.js +80 -0
  121. package/packages/task-core/src/task-events.js +101 -0
  122. package/packages/task-core/src/task-status.js +93 -0
  123. package/packages/task-core/src/task-store.js +74 -0
  124. package/packages/task-core/test/approvals.test.mjs +61 -0
  125. package/packages/task-core/test/controls.test.mjs +61 -0
  126. package/packages/task-core/test/replies.test.mjs +51 -0
  127. package/packages/task-core/test/task-events.test.mjs +67 -0
  128. package/packages/task-core/test/task-status.test.mjs +49 -0
  129. package/packages/task-core/test/task-store.test.mjs +65 -0
  130. package/test/harness.mjs +22 -0
  131. package/test/run-tests.mjs +47 -0
package/.gitattributes ADDED
@@ -0,0 +1,34 @@
1
+ * text=auto
2
+
3
+ # Source and documentation use LF across platforms.
4
+ *.js text eol=lf
5
+ *.mjs text eol=lf
6
+ *.json text eol=lf
7
+ *.html text eol=lf
8
+ *.css text eol=lf
9
+ *.md text eol=lf
10
+ *.yml text eol=lf
11
+ *.yaml text eol=lf
12
+ .gitignore text eol=lf
13
+ .gitattributes text eol=lf
14
+
15
+ # Windows command scripts keep CRLF.
16
+ *.bat text eol=crlf
17
+ *.cmd text eol=crlf
18
+ *.ps1 text eol=crlf
19
+
20
+ # Binary assets.
21
+ *.png binary
22
+ *.jpg binary
23
+ *.jpeg binary
24
+ *.gif binary
25
+ *.webp binary
26
+ *.ico binary
27
+ *.icns binary
28
+ *.woff binary
29
+ *.woff2 binary
30
+ *.ttf binary
31
+ *.otf binary
32
+ *.zip binary
33
+ *.gz binary
34
+ *.7z binary
@@ -0,0 +1,61 @@
1
+ name: Release
2
+
3
+ # Publish to npm when a version tag is pushed, e.g.:
4
+ # npm version patch # bumps package.json + creates a vX.Y.Z tag
5
+ # git push --follow-tags
6
+ # or manually:
7
+ # git tag v0.1.1 && git push origin v0.1.1
8
+ on:
9
+ push:
10
+ tags:
11
+ - "v*"
12
+
13
+ permissions:
14
+ contents: read
15
+ id-token: write # required for npm provenance (--provenance)
16
+
17
+ concurrency:
18
+ group: release-${{ github.ref }}
19
+ cancel-in-progress: false
20
+
21
+ jobs:
22
+ publish:
23
+ runs-on: ubuntu-latest
24
+ steps:
25
+ - name: Check out the tagged commit
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Set up Node.js
29
+ uses: actions/setup-node@v4
30
+ with:
31
+ node-version: 20
32
+ registry-url: "https://registry.npmjs.org"
33
+
34
+ - name: Install dependencies
35
+ # Electron's binary isn't needed to test or publish; skip the ~150 MB
36
+ # download so CI is fast and isn't at the mercy of the Electron CDN.
37
+ env:
38
+ ELECTRON_SKIP_BINARY_DOWNLOAD: "1"
39
+ run: npm ci
40
+
41
+ - name: Run the test suite
42
+ run: npm test
43
+
44
+ - name: Verify the tag matches package.json version
45
+ run: |
46
+ TAG="${GITHUB_REF_NAME#v}"
47
+ PKG="$(node -p "require('./package.json').version")"
48
+ echo "tag=$TAG package.json=$PKG"
49
+ if [ "$TAG" != "$PKG" ]; then
50
+ echo "::error::Tag v$TAG does not match package.json version $PKG"
51
+ exit 1
52
+ fi
53
+
54
+ - name: Publish to npm
55
+ env:
56
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
57
+ # --access public is needed for the first publish of a scoped package and
58
+ # harmless otherwise. --provenance attaches a signed build attestation
59
+ # (requires a public repo + the id-token permission above; drop it if the
60
+ # repo is private).
61
+ run: npm publish --provenance --access public
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ai Hayasaka
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,247 @@
1
+ <div align="center">
2
+
3
+ # 🐾 Haya Pet
4
+
5
+ ### One desktop companion for all your AI terminal agents
6
+
7
+ A transparent, draggable desktop pet that reflects what your AI CLIs are doing —
8
+ Codex, Claude Code, Antigravity, Aider, or any command — through one shared
9
+ runtime with client adapters.
10
+
11
+ <!-- HERO SCREENSHOT: drop a wide shot at docs/screenshots/hero.png
12
+ (the pet on the desktop with a couple of session bubbles) -->
13
+
14
+ ![Haya Pet on the desktop](docs/screenshots/hero.png)
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## What is this?
21
+
22
+ Most "desktop pet for an AI tool" projects build one pet per tool. Haya Pet does
23
+ the opposite: it is **one AI Terminal Pet Runtime** that many AI clients plug
24
+ into through adapters.
25
+
26
+ You might be running several agents at once:
27
+
28
+ ```text
29
+ Codex CLI → backend repo
30
+ Claude Code → frontend repo
31
+ Antigravity CLI → infra repo
32
+ Aider → docs repo
33
+ ```
34
+
35
+ Haya Pet watches all of them and presents one ambient interface:
36
+
37
+ - **One global pet** — reflects the selected or most urgent AI session; clickable,
38
+ draggable, and position-persistent like a real desktop companion.
39
+ - **Session bubbles** — one compact bubble per active session showing client,
40
+ project, the latest activity, and a status icon (a spinning *working* circle, a
41
+ green *done* check, a yellow *needs you*, or a red *failed* cross). A folder
42
+ button beside the pet folds them away.
43
+
44
+ ## Features
45
+
46
+ - 🪟 **Transparent, frameless, always-on-top overlay** that doesn't steal focus and
47
+ stays click-through outside the pet and bubbles.
48
+ - 🖱️ **Click / double-click / drag** — click folds/unfolds the bubbles, double-click
49
+ expands them, drag moves the pet (position persists; bubbles stay on-screen).
50
+ - 🟢 **Live session bubbles** with per-session status icons and a folder toggle.
51
+ - 🧠 **Normalized state model** — every client maps to a shared state vocabulary
52
+ (`thinking`, `running_tool`, `waiting_approval`, `reviewing`, `failed`, …).
53
+ - 🧩 **Client adapters** with tiered support (process wrapper → PTY observer →
54
+ log/state → official plugin) so the daemon never bakes in client-specific logic.
55
+ - 🚀 **Zero-setup launch** — `haya-pet run …` auto-starts the overlay; no separate
56
+ daemon to manage.
57
+ - 🖼️ **Codex-compatible pet assets** (1536×1872 sprite atlas, 9 actions).
58
+ - 🔒 **Local-only & private** — no prompts, files, or screenshots leave your machine.
59
+ - 🪟🍎🐧 **Cross-platform** core with per-OS adapters for IPC and windowing.
60
+
61
+ ## Screenshots
62
+
63
+ <!-- Drop each PNG into docs/screenshots/ with the filename shown (~800px wide).
64
+ Delete any row you don't have a shot for. -->
65
+
66
+ | | |
67
+ |---|---|
68
+ | **The global pet** — reacting to the highest-priority session.<br>![Pet overlay](docs/screenshots/pet-overlay.png) | **Session bubbles** — one per active session, with status icons.<br>![Session bubbles](docs/screenshots/session-bubbles.png) |
69
+ | **Folder collapsed** — bubbles tucked away beside the pet.<br>![Folder collapsed](docs/screenshots/folder-collapsed.png) | **Tray menu** — show/hide, pets, reset position, Quit.<br>![Tray menu](docs/screenshots/tray-menu.png) |
70
+
71
+ ## Documentation
72
+
73
+ | Doc | What's in it |
74
+ |---|---|
75
+ | **This README** | Install + users' guide |
76
+ | [docs/architecture.md](docs/architecture.md) | How it works, components, project structure, adapter tiers, platform matrix, native helpers, roadmap |
77
+ | [docs/publishing.md](docs/publishing.md) | Releasing to npm (the tag → publish workflow) |
78
+ | [docs/troubleshooting.md](docs/troubleshooting.md) | Common fixes, incl. repairing a broken Electron install |
79
+ | [docs/known-issues.md](docs/known-issues.md) | Deferred issues with known root causes |
80
+ | [docs/cross-os-qa.md](docs/cross-os-qa.md) | Cross-OS test matrix |
81
+ | [apps/companion/README.md](apps/companion/README.md) | Companion (Electron) internals |
82
+ | [PROGRESS.md](PROGRESS.md) | Detailed development log |
83
+
84
+ ---
85
+
86
+ # Users' Guide
87
+
88
+ ## Requirements
89
+
90
+ | Requirement | Why |
91
+ |---|---|
92
+ | **Node ≥ 18** | Runtime + companion (Electron) |
93
+ | **npm** | Install + scripts |
94
+
95
+ > Live activity status uses the optional `node-pty` (installed automatically when
96
+ > it can build; the pet degrades to lifecycle-only tracking without it).
97
+
98
+ ## Install
99
+
100
+ **From npm** *(once published — recommended for users):*
101
+
102
+ ```bash
103
+ npm install -g @hayasaka7/haya-pet # exposes the `haya-pet` command globally
104
+ ```
105
+
106
+ **From source** *(current):*
107
+
108
+ ```bash
109
+ git clone <repo-url> haya-pet
110
+ cd haya-pet
111
+ npm install
112
+ npm link # makes `haya-pet` available everywhere
113
+ ```
114
+
115
+ Prefer not to link globally? Call it directly anywhere you'd type `haya-pet`:
116
+ `node <repo>/apps/cli/src/haya-pet.js`.
117
+
118
+ ## Run an AI session
119
+
120
+ Just wrap any command. **The first `haya-pet run` auto-starts the pet overlay** —
121
+ there's nothing to launch first:
122
+
123
+ ```bash
124
+ haya-pet run --client codex -- codex
125
+ haya-pet run --client claude-code -- claude
126
+ haya-pet run --client generic -- aider
127
+ # Windows / PowerShell example:
128
+ haya-pet run --client generic -- powershell -Command "Start-Sleep 10"
129
+ ```
130
+
131
+ A **session bubble** appears while the command runs (client · project · status),
132
+ and the pet reflects the highest-priority session. On exit the bubble briefly
133
+ shows success (a green check) or failure (a red cross), then fades.
134
+
135
+ > If the overlay can't be started (e.g. Electron is missing), your command still
136
+ > runs normally and keeps its exit code — you just won't see the pet. Disable
137
+ > auto-start with `HAYA_PET_NO_AUTOSTART=1`, or launch it yourself with `haya-pet start`.
138
+
139
+ ### Live activity status
140
+
141
+ By default the wrapper runs the CLI through a pseudo-terminal and shows *working*
142
+ while the AI produces output, returning to *idle* after a short quiet window.
143
+ Success/failure come from the real exit code — never from scraping the word
144
+ "error" out of output. Your terminal stays fully interactive.
145
+
146
+ ```bash
147
+ haya-pet run -- claude # live status (default)
148
+ haya-pet run --no-observe -- claude # lifecycle only (opt out of PTY observation)
149
+ ```
150
+
151
+ > ⚠️ Running a CLI through the default PTY observation currently affects terminal
152
+ > scrolling and backspace in some setups — see
153
+ > [docs/known-issues.md](docs/known-issues.md). `--no-observe` avoids it.
154
+
155
+ ## Add and choose a pet
156
+
157
+ A pet is a folder with `pet.json` and a 1536×1872 sprite atlas (8×9 cells of
158
+ 192×208). Drop it into a search path:
159
+
160
+ ```text
161
+ ~/.codex/pets/my-pet/ (Windows: %USERPROFILE%\.codex\pets\my-pet\)
162
+ pet.json { "id": "my-pet", "name": "My Pet", "spritesheet": "spritesheet.webp" }
163
+ spritesheet.webp
164
+ ```
165
+
166
+ Pets are discovered from `~/.codex/pets` and `~/.haya-pet/pets`. Then choose one:
167
+
168
+ ```bash
169
+ haya-pet pets # list installed pets (* = selected)
170
+ haya-pet pets use my-pet # select; remembered on every launch
171
+ ```
172
+
173
+ Your choice is stored and reused every time. You can also pick from the tray menu
174
+ → **Installed Pets**. Without a spritesheet, the pet renders labelled placeholder
175
+ frames so everything still works.
176
+
177
+ ## Interact with the pet
178
+
179
+ | Action | Result |
180
+ |---|---|
181
+ | Single click | waves + folds/unfolds the session bubbles |
182
+ | Double click | jumps + expands the bubbles |
183
+ | Drag | moves the pet; position is saved (bubbles follow, always on-screen) |
184
+ | Tray icon → menu | show/hide, display mode, sessions, pets, **reset position**, **Quit** |
185
+
186
+ ## Stop / exit the pet
187
+
188
+ ```bash
189
+ haya-pet stop # ask the running overlay to quit
190
+ ```
191
+
192
+ …or **right-click the tray icon → Quit**. `haya-pet stop` is a no-op if nothing is
193
+ running, so it's always safe to call.
194
+
195
+ ## Manage the overlay
196
+
197
+ ```bash
198
+ haya-pet start # start the overlay explicitly (usually unnecessary — run auto-starts it)
199
+ haya-pet stop # quit it
200
+ ```
201
+
202
+ ## Troubleshooting
203
+
204
+ Common fixes:
205
+
206
+ | Symptom | Fix |
207
+ |---|---|
208
+ | `haya-pet: command not found` | Install globally, or `npm link` in a source checkout. |
209
+ | Pet doesn't react to a session | Launch via `haya-pet run …`; check `HAYA_PET_NO_AUTOSTART` isn't set. |
210
+ | Pet shows a blue placeholder box | No spritesheet — add a pet (above). |
211
+ | Pet is off-screen | Tray menu → **Reset Position**. |
212
+ | Can't exit | `haya-pet stop` or tray → **Quit**. |
213
+
214
+ Full list (incl. repairing a broken Electron install): [docs/troubleshooting.md](docs/troubleshooting.md).
215
+
216
+ ---
217
+
218
+ ## Supported clients
219
+
220
+ | Client | Status | Support level |
221
+ |---|---|---|
222
+ | Generic CLI | ✅ | L1 process wrapper |
223
+ | Codex | ✅ | L1 + L2 PTY observation |
224
+ | Claude Code | ✅ | L1 + L2 PTY observation |
225
+ | Antigravity | ✅ | L1 wrapper |
226
+ | Gemini CLI / Aider / others | 🔜 | via the generic adapter |
227
+
228
+ (See [docs/architecture.md](docs/architecture.md) for the support tiers and the
229
+ platform matrix.)
230
+
231
+ ## Privacy
232
+
233
+ Haya Pet is local-only by default. It does **not** upload prompts, files,
234
+ screenshots, or session logs; it stores only short derived status summaries.
235
+ Approvals always require explicit user action.
236
+
237
+ ## Contributing & tests
238
+
239
+ ```bash
240
+ npm test # runs the full suite (TDD; tests live in **/test/*.test.mjs)
241
+ ```
242
+
243
+ See [docs/architecture.md](docs/architecture.md) to find your way around the code.
244
+
245
+ ## License
246
+
247
+ See [`LICENSE`](LICENSE).