pi-character 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dominic Fezzie
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 CHANGED
@@ -1,3 +1,251 @@
1
- # Temporary Holding Version
1
+ # pi-character
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Animated ASCII companions for your Pi terminal. Pick a bundled character or generate your own.
4
+
5
+ ![Pi character demo: Cray at startup, live character previews, and a saved character in pink.](https://github.com/dfezzie/pi-character/raw/refs/heads/main/docs/media/demo.gif)
6
+
7
+ Captured from a real Pi session: startup, live previews, saving a selection, and changing its color.
8
+ The terminal view is cropped to the character and controls. No model tokens were used.
9
+
10
+ Characters play locally, with no model calls or token usage at startup. Requires **Pi 1.4.0+**;
11
+ no custom Pi build or additional runtime dependencies are needed.
12
+
13
+ ## Quick start
14
+
15
+ Install the published package from npm:
16
+
17
+ ```sh
18
+ pi install npm:pi-character
19
+ ```
20
+
21
+ Restart Pi or run `/reload`. **Cray the Crawfish** appears alongside Pi's original startup header.
22
+
23
+ Open the character menu:
24
+
25
+ ```text
26
+ /character
27
+ ```
28
+
29
+ Choose **Choose character**, then use **↑ / ↓** to preview the animations. Press **Enter** to save
30
+ your choice, or **Escape** to return to your previous character.
31
+
32
+ ## Meet the characters
33
+
34
+ Five characters are included and ready to use:
35
+
36
+ - **Cray the Crawfish** — the default welcome character.
37
+ - **Dozy the Fox Wizard** — a sleepy fox in a wizard hat.
38
+ - **Arlo the Armadillo** — an armored companion with a tail wag.
39
+ - **Ori the Oriole** — a little bird perched on a twig.
40
+ - **Fern the Fox** — a woodland fox with a bushy tail.
41
+
42
+ Your selection and color preference are remembered across restarts.
43
+
44
+ ## Everyday controls
45
+
46
+ | Command | What it does |
47
+ | ------------------- | ------------------------------------------------------ |
48
+ | `/character` | Open the menu |
49
+ | `/character select` | Browse bundled and saved characters with live previews |
50
+ | `/character color` | Choose a color |
51
+ | `/character show` | Enable and display your selected character |
52
+ | `/character off` | Hide the character, including on future starts |
53
+
54
+ In the character picker:
55
+
56
+ | Key | What it does |
57
+ | ---------- | -------------------------------------------------------------------- |
58
+ | **↑ / ↓** | Preview the highlighted character |
59
+ | **Enter** | Save your selection |
60
+ | **Escape** | Restore your previous character and visibility |
61
+ | **r** | Generate a new version of the highlighted character; **uses tokens** |
62
+ | **d** | Delete the highlighted character after confirmation |
63
+
64
+ Characters hide while you type or when the terminal is too small. Starting an agent task hides
65
+ the character for the rest of that session; use `/character show` to bring it back. It appears
66
+ again in a new session unless you turned it off.
67
+
68
+ ### Colors
69
+
70
+ By default, the artwork and name follow Pi's theme accent. Use the color menu or set one directly:
71
+
72
+ ```text
73
+ /character color default
74
+ /character color original
75
+ /character color pink
76
+ ```
77
+
78
+ `original` uses the character's own palette color. Fixed colors are `cyan`, `orange`, `green`,
79
+ `pink`, `blue`, and `yellow`. Colors persist across character changes and restarts.
80
+ Setting `NO_COLOR` disables the character's ANSI palette.
81
+
82
+ ## Generate your own
83
+
84
+ **Generation and rerolls use model tokens.** Playing saved or bundled characters is local.
85
+
86
+ Describe a character using Pi's current model and authentication:
87
+
88
+ ```text
89
+ /character generate a tiny moon wearing headphones
90
+ ```
91
+
92
+ Each result is animated for preview before you decide:
93
+
94
+ - **Keep character** saves it to your library and selects it.
95
+ - **Reroll (uses tokens)** generates another attempt.
96
+ - **Cancel** restores your previous character without saving the preview.
97
+
98
+ To stop an in-progress request:
99
+
100
+ ```text
101
+ /character cancel
102
+ ```
103
+
104
+ Cancellation is available during generation and preview. Once the final preferences
105
+ write begins after **Keep character**, saving finishes before character commands
106
+ are available again. If a command arrives during that brief step, Pi asks you to
107
+ retry after the save finishes.
108
+
109
+ You can also press **r** in the picker to reroll an existing character. This reuses its description
110
+ and original generation model when available. The saved version is replaced only after you keep
111
+ a valid result.
112
+
113
+ ### Choose a generation model
114
+
115
+ List models registered in Pi, then select one for a single generation:
116
+
117
+ ```text
118
+ /character models
119
+ /character generate --model provider/model-id a tiny moon wearing headphones
120
+ ```
121
+
122
+ The override applies only to that request; it leaves your Pi session model and global settings
123
+ unchanged. A model's presence in the catalog does not guarantee that your provider account can
124
+ use it.
125
+
126
+ ### What gets sent and saved
127
+
128
+ Generation sends a dedicated character prompt and your description through Pi's model registry.
129
+ It does not send your coding conversation or tools, and the result is not added to conversation
130
+ history. Requests time out after two minutes and are never retried automatically. Failed or
131
+ invalid results leave your existing character usable.
132
+
133
+ Only previews you keep enter your library. Generated artwork is validated JSON data and is never
134
+ executed as code.
135
+
136
+ ## Import and storage
137
+
138
+ Import a character JSON file in the original Codex prototype format or as a bare sprite:
139
+
140
+ ```text
141
+ /character import /path/to/character.json
142
+ ```
143
+
144
+ Characters and preferences live in `~/.pi/agent/characters/`, or in `characters/` under
145
+ `PI_CODING_AGENT_DIR` when set. The directory contains JSON assets with generation metadata and
146
+ `settings.json` for your selection, color, and enabled state.
147
+
148
+ Deleting a character from the picker archives it in `characters/.trash/`. Deleted characters stay
149
+ out of the picker across restarts, including bundled presets.
150
+
151
+ ## Uninstall
152
+
153
+ ```sh
154
+ pi remove npm:pi-character
155
+ ```
156
+
157
+ Your saved characters and preferences remain. To reset them as well, separately delete the
158
+ characters directory described above.
159
+
160
+ ## Development
161
+
162
+ Use Node **22.19+**. Install development dependencies, then run the checks and offline tests:
163
+
164
+ ```sh
165
+ npm ci --legacy-peer-deps
166
+ npm run build
167
+ ```
168
+
169
+ To load the checkout for a single Pi session:
170
+
171
+ ```sh
172
+ pi -e /path/to/pi-character
173
+ ```
174
+
175
+ To install a local checkout instead, use its absolute path:
176
+
177
+ ```sh
178
+ pi install /path/to/pi-character
179
+ ```
180
+
181
+ Remove a local installation with `pi remove /path/to/pi-character`. Pass the package directory so
182
+ Pi reads its manifest and loads only `src/index.ts`. Use one loading method at a time: npm, local
183
+ installation, or `-e`.
184
+
185
+ ### Project layout
186
+
187
+ ```text
188
+ src/
189
+ index.ts Pi lifecycle, widget, menus, and commands
190
+ character.ts Character validation, storage, and frame layout
191
+ generation.ts Model requests, cancellation, and errors
192
+ assets/ Bundled character JSON presets
193
+ test/ Unit tests, fixtures, and terminal smoke harness
194
+ ```
195
+
196
+ Application code lives in `src/`, tests in `test/`, and presets in `assets/`. Tooling configuration
197
+ stays at the package root. Pi loads TypeScript source directly, so no compilation or `dist/`
198
+ directory is needed. Pi supplies its API and terminal UI packages at runtime.
199
+
200
+ ### Code reviews
201
+
202
+ In a repository checkout, ask **review the current changes** (or name a commit range or
203
+ component). [The review workflow](docs/code-review.md) runs three independent Orca reviewers
204
+ for correctness, maintainability, and verification, followed by a separate pragmatic decider.
205
+ Reviews are read-only by default. The decider accepts or rejects suggestions based on evidence,
206
+ readability, maintenance cost, and this package's small scope.
207
+
208
+ ### Checks
209
+
210
+ | Command | What it checks |
211
+ | ----------------------------------------- | ------------------------------------------------------------------------- |
212
+ | `npm run build` | Lint, formatting, types, and offline tests |
213
+ | `npm run check` | Lint, formatting, and types |
214
+ | `npm test` | Offline asset, generation, storage, lifecycle, and terminal-harness tests |
215
+ | `npm run test:smoke` | This checkout in a real Pi PTY with isolated temporary configuration |
216
+ | `npm run lint` / `npm run lint:fix` | ESLint checks / fixes |
217
+ | `npm run format` / `npm run format:check` | Prettier formatting / checks |
218
+ | `npm run typecheck` | TypeScript checks for source, tests, and tooling |
219
+
220
+ Run `node test/smoke.ts` to check the local package already installed in Pi. Add
221
+ `--generate --model provider/model-id` to spend tokens on one generation; this copies provider
222
+ credentials into temporary state, which is removed after the run. Add `--output /path/to/evidence`
223
+ to save terminal snapshots and generated assets.
224
+
225
+ The terminal harness uses `node-pty` and `@xterm/headless` and has been verified on macOS. Platforms
226
+ without a compatible prebuilt PTY binary require native build tools to install `node-pty`.
227
+
228
+ ### Presets and packaging
229
+
230
+ To ship a preset, add its reviewed JSON to `assets/` and the startup preset list in `src/index.ts`.
231
+ Personal generations live outside the repository. Local `generated/` exports and `validation/`
232
+ test artifacts are gitignored.
233
+
234
+ Assets are limited to 64 KiB, printable ASCII, 4–12 frames, 4–14 rows, 36 columns, a fixed palette,
235
+ and 80–600 ms frame durations. Animation timers are released on widget replacement, task start,
236
+ reload, and exit.
237
+
238
+ Run `npm pack --dry-run` or `npm pack` to review release contents. Packing runs `npm run build`;
239
+ the package includes source, presets, demo media, README, and license. Asset paths resolve relative to the
240
+ extension module, so playback works from any working directory.
241
+
242
+ ### Release
243
+
244
+ ```sh
245
+ npm run release
246
+ ```
247
+
248
+ Checks the package, bumps the patch version, and asks before publishing to npm.
249
+ Run `npm run release -- --help` for options.
250
+
251
+ Licensed under [MIT](LICENSE).
@@ -0,0 +1,78 @@
1
+ {
2
+ "version": 1,
3
+ "description": "Arlo the armadillo, adapted from the original Dillo prototype: domed armored shell, low pointed face, blink and tail wag.",
4
+ "model": null,
5
+ "sprite": {
6
+ "name": "Arlo the Armadillo",
7
+ "color": "orange",
8
+ "frame_ms": 200,
9
+ "frames": [
10
+ [
11
+ " .-======-.",
12
+ " .' / / / / '.",
13
+ " / / / / / / \\",
14
+ " /__/__/__/__/___\\",
15
+ " | / / / | o '--.",
16
+ " ___|_/__/__/___| _>",
17
+ " /___/ '---'",
18
+ " || ||",
19
+ " ^^ ^^"
20
+ ],
21
+ [
22
+ " .-======-.",
23
+ " .' / / / / '.",
24
+ " / / / / / / \\",
25
+ " /__/__/__/__/___\\",
26
+ " _ | / / / | o '--.",
27
+ " / \\_|_/__/__/___| _>",
28
+ " / '---'",
29
+ " || ||",
30
+ " ^^ ^^"
31
+ ],
32
+ [
33
+ " .-======-.",
34
+ " .' / / / / '.",
35
+ " / / / / / / \\",
36
+ " _ /__/__/__/__/___\\",
37
+ " / | | / / / | - '--.",
38
+ " \\_|_/__/__/___| _>",
39
+ " / '---'",
40
+ " || ||",
41
+ " ^^ ^^"
42
+ ],
43
+ [
44
+ " .-======-.",
45
+ " .' / / / / '.",
46
+ " / / / / / / \\",
47
+ " /__/__/__/__/___\\",
48
+ " _ | / / / | o '--.",
49
+ " / \\_|_/__/__/___| _>",
50
+ " / '---'",
51
+ " || ||",
52
+ " ^^ ^^"
53
+ ],
54
+ [
55
+ " .-======-.",
56
+ " .' / / / / '.",
57
+ " / / / / / / \\",
58
+ " /__/__/__/__/___\\",
59
+ " | / / / | o '--.",
60
+ " ___|_/__/__/___| _>",
61
+ " /___/ '---'",
62
+ " || ||",
63
+ " ^^ ^^"
64
+ ],
65
+ [
66
+ " .-======-.",
67
+ " .' / / / / '.",
68
+ " / / / / / / \\",
69
+ " /__/__/__/__/___\\",
70
+ " | / / / | o '--.",
71
+ " |_/__/__/___| _>",
72
+ " __/ '---'",
73
+ " /_/ || ||",
74
+ " ^^ ^^"
75
+ ]
76
+ ]
77
+ }
78
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "version": 1,
3
+ "description": "crawfish",
4
+ "model": null,
5
+ "sprite": {
6
+ "name": "Cray the Crawfish",
7
+ "color": "orange",
8
+ "frame_ms": 200,
9
+ "frames": [
10
+ [
11
+ " \\ / ",
12
+ " \\ / ",
13
+ " (\\ o o /) ",
14
+ " ( > /----\\ < ) ",
15
+ " \\_/| |\\_/ ",
16
+ " /|----|\\ ",
17
+ " / |----| \\ ",
18
+ " |----| ",
19
+ " \\==/ ",
20
+ " /_||_\\ "
21
+ ],
22
+ [
23
+ " \\ / ",
24
+ " \\ / ",
25
+ " (\\ o o /) ",
26
+ " ( > /----\\ < ) ",
27
+ " \\_/| |\\_/ ",
28
+ " /|----|\\ ",
29
+ " / |----| \\ ",
30
+ " |----| ",
31
+ " \\==/ ",
32
+ " /_||_\\ "
33
+ ],
34
+ [
35
+ " \\ / ",
36
+ " \\ / /) ",
37
+ " (\\ o o < ) ",
38
+ " ( > /----\\ / ",
39
+ " \\_/| |/ ",
40
+ " /|----|\\ ",
41
+ " / |----| \\ ",
42
+ " |----| ",
43
+ " \\==/ ",
44
+ " /_||_\\ "
45
+ ],
46
+ [
47
+ " \\ / ",
48
+ " \\ / /) ",
49
+ " (\\ - - < ) ",
50
+ " ( > /----\\ / ",
51
+ " \\_/| |/ ",
52
+ " /|----|\\ ",
53
+ " / |----| \\ ",
54
+ " |----| ",
55
+ " \\==/ ",
56
+ " /_||_\\ "
57
+ ],
58
+ [
59
+ " \\ / ",
60
+ " \\ / /) ",
61
+ " (\\ o o < ) ",
62
+ " ( > /----\\ / ",
63
+ " \\_/| |/ ",
64
+ " /|----|\\ ",
65
+ " / |----| \\ ",
66
+ " |----| ",
67
+ " \\==/ ",
68
+ " /_||_\\ "
69
+ ],
70
+ [
71
+ " \\ / ",
72
+ " \\ / ",
73
+ " (\\ o o /) ",
74
+ " ( > /----\\ < ) ",
75
+ " \\_/| |\\_/ ",
76
+ " /|----|\\ ",
77
+ " / |----| \\ ",
78
+ " |----| ",
79
+ " \\==/ ",
80
+ " /_||_\\ "
81
+ ]
82
+ ]
83
+ },
84
+ "usage": {
85
+ "input_tokens": 17065,
86
+ "cached_input_tokens": 0,
87
+ "cache_write_input_tokens": 0,
88
+ "output_tokens": 568,
89
+ "reasoning_output_tokens": 43
90
+ }
91
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "version": 1,
3
+ "description": "a sleepy orange fox wearing a wizard hat",
4
+ "model": null,
5
+ "sprite": {
6
+ "name": "Dozy the Fox Wizard",
7
+ "color": "orange",
8
+ "frame_ms": 220,
9
+ "frames": [
10
+ [
11
+ " /\\",
12
+ " / .\\",
13
+ " / * \\",
14
+ " /______\\",
15
+ " /\\ /\\",
16
+ " / o o \\",
17
+ " \\ \\/ /",
18
+ " \\______/_ /\\",
19
+ " / \\ \\_/ /",
20
+ " (_/____\\_)___/"
21
+ ],
22
+ [
23
+ " /\\",
24
+ " / .\\",
25
+ " / * \\",
26
+ " /______\\",
27
+ " /\\ /\\",
28
+ " / o o \\",
29
+ " \\ \\/ /",
30
+ " \\______/_ /\\",
31
+ " / \\ \\__/ /",
32
+ " (_/____\\_)____/"
33
+ ],
34
+ [
35
+ " /\\",
36
+ " / .\\",
37
+ " / * \\",
38
+ " /______\\",
39
+ " /\\ /\\",
40
+ " / - - \\",
41
+ " \\ \\/ /",
42
+ " \\______/_ /\\",
43
+ " / \\ \\___/ /",
44
+ " (_/____\\_)_____/"
45
+ ],
46
+ [
47
+ " /\\",
48
+ " / .\\",
49
+ " / * \\",
50
+ " /______\\",
51
+ " /\\ /\\",
52
+ " / - - \\",
53
+ " \\ \\/ /",
54
+ " \\______/_ /\\",
55
+ " / \\ \\__/ /",
56
+ " (_/____\\_)____/"
57
+ ],
58
+ [
59
+ " /\\",
60
+ " / .\\",
61
+ " / * \\",
62
+ " /______\\",
63
+ " /\\ /\\",
64
+ " / - o \\",
65
+ " \\ \\/ /",
66
+ " \\______/_ /\\",
67
+ " / \\ \\_/ /",
68
+ " (_/____\\_)___/"
69
+ ],
70
+ [
71
+ " /\\",
72
+ " / .\\",
73
+ " / * \\",
74
+ " /______\\",
75
+ " /\\ /\\",
76
+ " / o o \\",
77
+ " \\ \\/ /",
78
+ " \\______/_ /\\",
79
+ " / \\ \\_/ /",
80
+ " (_/____\\_)___/"
81
+ ]
82
+ ]
83
+ },
84
+ "usage": {
85
+ "input_tokens": 17066,
86
+ "cached_input_tokens": 0,
87
+ "cache_write_input_tokens": 0,
88
+ "output_tokens": 505,
89
+ "reasoning_output_tokens": 54
90
+ }
91
+ }
@@ -0,0 +1,84 @@
1
+ {
2
+ "version": 1,
3
+ "description": "A friendly ordinary woodland fox named Fern, seated with tall pointed ears, narrow muzzle and a large bushy tail curling beside its paws. No wizard hat or clothing, distinct from Dozy the wizard fox. Use orange color. Animate a blink and a tail tip wag.",
4
+ "model": "openai/gpt-6.1-sol",
5
+ "sprite": {
6
+ "name": "Fern the Fox",
7
+ "color": "orange",
8
+ "frame_ms": 200,
9
+ "frames": [
10
+ [
11
+ " /\\ /\\",
12
+ " / \\_/ \\",
13
+ " / o o \\",
14
+ " \\ ^ /",
15
+ " \\ \\_/ / __",
16
+ " /`-----'\\ .' )",
17
+ " / | | \\ / /",
18
+ " / | | \\ ( /",
19
+ " \\___|___|___/--\\ (",
20
+ " /_/ \\_\\ \\___`--'"
21
+ ],
22
+ [
23
+ " /\\ /\\",
24
+ " / \\_/ \\",
25
+ " / o o \\",
26
+ " \\ ^ /",
27
+ " \\ \\_/ / __",
28
+ " /`-----'\\ .' /",
29
+ " / | | \\ / /",
30
+ " / | | \\ ( /",
31
+ " \\___|___|___/--\\ (",
32
+ " /_/ \\_\\ \\___`--'"
33
+ ],
34
+ [
35
+ " /\\ /\\",
36
+ " / \\_/ \\",
37
+ " / - - \\",
38
+ " \\ ^ /",
39
+ " \\ \\_/ / __",
40
+ " /`-----'\\ .' /",
41
+ " / | | \\ / /",
42
+ " / | | \\ ( /",
43
+ " \\___|___|___/--\\ (",
44
+ " /_/ \\_\\ \\___`--'"
45
+ ],
46
+ [
47
+ " /\\ /\\",
48
+ " / \\_/ \\",
49
+ " / o o \\",
50
+ " \\ ^ /",
51
+ " \\ \\_/ / __",
52
+ " /`-----'\\ .' )",
53
+ " / | | \\ / /",
54
+ " / | | \\ ( /",
55
+ " \\___|___|___/--\\ (",
56
+ " /_/ \\_\\ \\___`--'"
57
+ ],
58
+ [
59
+ " /\\ /\\",
60
+ " / \\_/ \\",
61
+ " / o o \\",
62
+ " \\ ^ /",
63
+ " \\ \\_/ / __",
64
+ " /`-----'\\ .' )",
65
+ " / | | \\ / /",
66
+ " / | | \\ ( /",
67
+ " \\___|___|___/--\\ (",
68
+ " /_/ \\_\\ \\___`--'"
69
+ ],
70
+ [
71
+ " /\\ /\\",
72
+ " / \\_/ \\",
73
+ " / o o \\",
74
+ " \\ ^ /",
75
+ " \\ \\_/ / __",
76
+ " /`-----'\\ .' )",
77
+ " / | | \\ / /",
78
+ " / | | \\ ( /",
79
+ " \\___|___|___/--\\ (",
80
+ " /_/ \\_\\ \\___`--'"
81
+ ]
82
+ ]
83
+ }
84
+ }