@underactive/pi-topping 0.6.0 → 0.6.2

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/README.md CHANGED
@@ -71,6 +71,12 @@ Run `/topping-settings` (TUI only) to customize your toppings. Settings persist
71
71
  ║ [■] Mid-turn inputs ON ║
72
72
  ║ ║
73
73
  ╟─ Word Packs ───────────────────────────────────────────────╢
74
+ ║ [ ] Doctor Who OFF ║
75
+ ║ [ ] Firefly OFF ║
76
+ ║ [ ] Hitchhiker's Guide OFF ║
77
+ ║ [ ] The Lord of the Rings OFF ║
78
+ ║ [ ] The Matrix OFF ║
79
+ ║ [ ] Portal OFF ║
74
80
  ║ [ ] SimCity OFF ║
75
81
  ║ [ ] Star Trek OFF ║
76
82
  ║ [ ] Star Wars OFF ║
@@ -79,14 +85,14 @@ Run `/topping-settings` (TUI only) to customize your toppings. Settings persist
79
85
  ║ [■] Use NerdFont icons ON ║
80
86
  ╟────────────────────────────────────────────────────────────╢
81
87
  ║ ↑↓ move ←→ select ␣ toggle ⏎ apply esc cancel ║
82
- ╚════════════════════════════════════════════════════[ 9/41 ]╝
88
+ ╚════════════════════════════════════════════════════[ 9/47 ]╝
83
89
  ```
84
90
 
85
91
  ### Word packs
86
92
 
87
- Base activity words are always available. All word packs, including the shipped **SimCity**, **Star Trek**, and **Star Wars** packs and custom packs, are disabled by default. Enable packs in `/topping-settings` to add their entries to the same uniformly selected pool. When Randomize “Worked” text is on, the completion marker uses the selected entry’s matching past tense; otherwise it uses `Worked`.
93
+ Base activity words are always available. All word packs, including the shipped **Doctor Who**, **Firefly**, **Hitchhiker's Guide**, **The Lord of the Rings**, **The Matrix**, **Portal**, **SimCity**, **Star Trek**, and **Star Wars** packs and custom packs, are disabled by default. Enable packs in `/topping-settings` to add their entries to the same uniformly selected pool. When Randomize “Worked” text is on, the completion marker uses the selected entry’s matching past tense; otherwise it uses `Worked`.
88
94
 
89
- Bundled packs live in [`wordpacks/`](wordpacks/). Copy `wordpacks/simcity.json`, `wordpacks/star-trek.json`, or `wordpacks/star-wars.json` to `~/.pi/agent/pi-topping/word-packs.json`, then change the pack `id` (the bundled `simcity`, `star-trek`, and `star-wars` IDs are reserved), name, and words:
95
+ Bundled packs live in [`wordpacks/`](wordpacks/). Copy `wordpacks/doctor-who.json`, `wordpacks/firefly.json`, `wordpacks/hitchhikers-guide.json`, `wordpacks/lord-of-the-rings.json`, `wordpacks/matrix.json`, `wordpacks/portal.json`, `wordpacks/simcity.json`, `wordpacks/star-trek.json`, or `wordpacks/star-wars.json` to `~/.pi/agent/pi-topping/word-packs.json`, then change the pack `id` (the bundled `doctor-who`, `firefly`, `hitchhikers-guide`, `lord-of-the-rings`, `matrix`, `portal`, `simcity`, `star-trek`, and `star-wars` IDs are reserved), name, and words:
90
96
 
91
97
  ```json
92
98
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@underactive/pi-topping",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "A Pi extension that adds quality of life improvements to Pi's UX: a high-vis user prompt, a shimmering working loader with token activity meter and elapsed timer, and an end-of-turn completion marker",
5
5
  "keywords": ["pi-package", "pi-extension"],
6
6
  "license": "MIT",
package/src/menu.ts CHANGED
@@ -355,6 +355,12 @@ export class MenuComponent implements Component {
355
355
  const flat = this.flat[index]!;
356
356
  if (flat.sectionIndex !== currentSection) {
357
357
  const remaining = maxRows - lines.length;
358
+ // A section continued from above needs room for a blank separator
359
+ // row, its divider, and at least one item row; otherwise end the
360
+ // window here rather than crowd the divider against the previous
361
+ // section or fold the section into it. The window's first section
362
+ // always renders (a degenerate window may drop its divider).
363
+ if (lines.length > 0 && remaining < 3) break;
358
364
  if (lines.length > 0 && remaining >= 3) lines.push(this.renderBlankRow(innerWidth));
359
365
  if (maxRows - lines.length >= 2) lines.push(this.renderSectionDivider(this.sections[flat.sectionIndex]!.title, innerWidth));
360
366
  currentSection = flat.sectionIndex;
@@ -380,18 +386,25 @@ export class MenuComponent implements Component {
380
386
  if (this.cursor < this.scrollStart) this.scrollStart = this.cursor;
381
387
  this.scrollStart = Math.max(0, Math.min(this.scrollStart, this.flat.length - 1));
382
388
 
383
- let window = this.buildToggleWindow(innerWidth, this.scrollStart, contentRows);
384
- while (window.end < this.cursor && this.scrollStart < this.cursor) {
385
- this.scrollStart++;
386
- window = this.buildToggleWindow(innerWidth, this.scrollStart, contentRows);
387
- }
388
- // Backfill from above whenever more context fits without hiding the cursor.
389
- while (this.scrollStart > 0) {
390
- const candidate = this.buildToggleWindow(innerWidth, this.scrollStart - 1, contentRows);
391
- if (candidate.end < this.cursor) break;
392
- this.scrollStart--;
393
- window = candidate;
389
+ // Walk backward from cursor to find the lowest scrollStart that fits in contentRows.
390
+ {
391
+ let rowsUsed = 2; // 1 for cursor item + 1 for first-section divider
392
+ let section = this.flat[this.cursor]!.sectionIndex;
393
+ this.scrollStart = this.cursor;
394
+ for (let i = this.cursor - 1; i >= 0; i--) {
395
+ const sec = this.flat[i]!.sectionIndex;
396
+ if (sec !== section) {
397
+ if (rowsUsed + 3 > contentRows) break;
398
+ rowsUsed += 3;
399
+ section = sec;
400
+ } else {
401
+ if (rowsUsed + 1 > contentRows) break;
402
+ rowsUsed += 1;
403
+ }
404
+ this.scrollStart = i;
405
+ }
394
406
  }
407
+ const window = this.buildToggleWindow(innerWidth, this.scrollStart, contentRows);
395
408
 
396
409
  const rows = [...window.lines];
397
410
  while (rows.length < contentRows) rows.push(this.renderBlankRow(innerWidth));
package/src/word-packs.ts CHANGED
@@ -6,7 +6,7 @@ import { isPlainObject, stripControlChars } from "./util.ts";
6
6
  import { WORDS, type WordEntry } from "./words.ts";
7
7
 
8
8
  const PACK_ID_PATTERN = /^[a-z][a-z0-9-]{0,63}$/;
9
- const RESERVED_BUNDLED_PACK_IDS = new Set(["simcity", "star-trek", "star-wars"]);
9
+ const RESERVED_BUNDLED_PACK_IDS = new Set(["doctor-who", "firefly", "hitchhikers-guide", "lord-of-the-rings", "matrix", "portal", "simcity", "star-trek", "star-wars"]);
10
10
 
11
11
  export function isWordPackId(value: string): boolean { return PACK_ID_PATTERN.test(value); }
12
12
  const BUNDLED_PACK_DIRECTORY = fileURLToPath(new URL("../wordpacks/", import.meta.url));
@@ -0,0 +1,283 @@
1
+ {
2
+ "packs": [
3
+ {
4
+ "id": "doctor-who",
5
+ "name": "Doctor Who",
6
+ "description": "Time Lord operations across all of time and space.",
7
+ "words": [
8
+ {
9
+ "present_tense": "Answering TARDIS phone",
10
+ "past_tense": "Answered"
11
+ },
12
+ {
13
+ "present_tense": "Asking oldest question",
14
+ "past_tense": "Asked"
15
+ },
16
+ {
17
+ "present_tense": "Avoiding spoilers",
18
+ "past_tense": "Avoided"
19
+ },
20
+ {
21
+ "present_tense": "Baking impossible soufflé",
22
+ "past_tense": "Baked"
23
+ },
24
+ {
25
+ "present_tense": "Becoming Bad Wolf",
26
+ "past_tense": "Became"
27
+ },
28
+ {
29
+ "present_tense": "Befriending Ood",
30
+ "past_tense": "Befriended"
31
+ },
32
+ {
33
+ "present_tense": "Bootstrapping paradox",
34
+ "past_tense": "Bootstrapped"
35
+ },
36
+ {
37
+ "present_tense": "Breaking time lock",
38
+ "past_tense": "Broke"
39
+ },
40
+ {
41
+ "present_tense": "Brewing tea",
42
+ "past_tense": "Brewed"
43
+ },
44
+ {
45
+ "present_tense": "Calibrating chameleon circuit",
46
+ "past_tense": "Calibrated"
47
+ },
48
+ {
49
+ "present_tense": "Charging sonic screwdriver",
50
+ "past_tense": "Charged"
51
+ },
52
+ {
53
+ "present_tense": "Counting shadows",
54
+ "past_tense": "Counted"
55
+ },
56
+ {
57
+ "present_tense": "Crossing own timeline",
58
+ "past_tense": "Crossed"
59
+ },
60
+ {
61
+ "present_tense": "Dematerializing TARDIS",
62
+ "past_tense": "Dematerialized"
63
+ },
64
+ {
65
+ "present_tense": "Detecting temporal anomaly",
66
+ "past_tense": "Detected"
67
+ },
68
+ {
69
+ "present_tense": "Dodging Dalek plunger",
70
+ "past_tense": "Dodged"
71
+ },
72
+ {
73
+ "present_tense": "Donning fez",
74
+ "past_tense": "Donned"
75
+ },
76
+ {
77
+ "present_tense": "Eating fish fingers and custard",
78
+ "past_tense": "Ate"
79
+ },
80
+ {
81
+ "present_tense": "Escaping collapsed star",
82
+ "past_tense": "Escaped"
83
+ },
84
+ {
85
+ "present_tense": "Evading Cybermen",
86
+ "past_tense": "Evaded"
87
+ },
88
+ {
89
+ "present_tense": "Explaining wibbly-wobbly timey-wimey",
90
+ "past_tense": "Explained"
91
+ },
92
+ {
93
+ "present_tense": "Exterminating bugs",
94
+ "past_tense": "Exterminated"
95
+ },
96
+ {
97
+ "present_tense": "Flashing psychic paper",
98
+ "past_tense": "Flashed"
99
+ },
100
+ {
101
+ "present_tense": "Flying TARDIS solo",
102
+ "past_tense": "Flew"
103
+ },
104
+ {
105
+ "present_tense": "Forgetting Silence",
106
+ "past_tense": "Forgot"
107
+ },
108
+ {
109
+ "present_tense": "Growing new hand",
110
+ "past_tense": "Grew"
111
+ },
112
+ {
113
+ "present_tense": "Guarding Pandorica",
114
+ "past_tense": "Guarded"
115
+ },
116
+ {
117
+ "present_tense": "Hacking UNIT database",
118
+ "past_tense": "Hacked"
119
+ },
120
+ {
121
+ "present_tense": "Hearing drums",
122
+ "past_tense": "Heard"
123
+ },
124
+ {
125
+ "present_tense": "Hiding from Weeping Angels",
126
+ "past_tense": "Hid"
127
+ },
128
+ {
129
+ "present_tense": "Improvising escape plan",
130
+ "past_tense": "Improvised"
131
+ },
132
+ {
133
+ "present_tense": "Jamming Cybermen signal",
134
+ "past_tense": "Jammed"
135
+ },
136
+ {
137
+ "present_tense": "Knitting impossibly long scarf",
138
+ "past_tense": "Knitted"
139
+ },
140
+ {
141
+ "present_tense": "Knocking four times",
142
+ "past_tense": "Knocked"
143
+ },
144
+ {
145
+ "present_tense": "Landing in wrong century",
146
+ "past_tense": "Landed"
147
+ },
148
+ {
149
+ "present_tense": "Leaving brakes on",
150
+ "past_tense": "Left"
151
+ },
152
+ {
153
+ "present_tense": "Materializing in Victorian London",
154
+ "past_tense": "Materialized"
155
+ },
156
+ {
157
+ "present_tense": "Meeting past selves",
158
+ "past_tense": "Met"
159
+ },
160
+ {
161
+ "present_tense": "Monitoring crack in time",
162
+ "past_tense": "Monitored"
163
+ },
164
+ {
165
+ "present_tense": "Navigating time vortex",
166
+ "past_tense": "Navigated"
167
+ },
168
+ {
169
+ "present_tense": "Negotiating with Zygons",
170
+ "past_tense": "Negotiated"
171
+ },
172
+ {
173
+ "present_tense": "Offering jelly babies",
174
+ "past_tense": "Offered"
175
+ },
176
+ {
177
+ "present_tense": "Outrunning Daleks",
178
+ "past_tense": "Outran"
179
+ },
180
+ {
181
+ "present_tense": "Parking TARDIS",
182
+ "past_tense": "Parked"
183
+ },
184
+ {
185
+ "present_tense": "Playing guitar on tank",
186
+ "past_tense": "Played"
187
+ },
188
+ {
189
+ "present_tense": "Practicing Venusian aikido",
190
+ "past_tense": "Practiced"
191
+ },
192
+ {
193
+ "present_tense": "Pressing big friendly button",
194
+ "past_tense": "Pressed"
195
+ },
196
+ {
197
+ "present_tense": "Priming vortex manipulator",
198
+ "past_tense": "Primed"
199
+ },
200
+ {
201
+ "present_tense": "Pulling wibbly lever",
202
+ "past_tense": "Pulled"
203
+ },
204
+ {
205
+ "present_tense": "Reading Gallifreyan",
206
+ "past_tense": "Read"
207
+ },
208
+ {
209
+ "present_tense": "Rebooting universe",
210
+ "past_tense": "Rebooted"
211
+ },
212
+ {
213
+ "present_tense": "Refueling at Cardiff rift",
214
+ "past_tense": "Refueled"
215
+ },
216
+ {
217
+ "present_tense": "Refusing to blink",
218
+ "past_tense": "Refused"
219
+ },
220
+ {
221
+ "present_tense": "Regenerating",
222
+ "past_tense": "Regenerated"
223
+ },
224
+ {
225
+ "present_tense": "Rerouting temporal circuits",
226
+ "past_tense": "Rerouted"
227
+ },
228
+ {
229
+ "present_tense": "Rescuing companions",
230
+ "past_tense": "Rescued"
231
+ },
232
+ {
233
+ "present_tense": "Resetting time loop",
234
+ "past_tense": "Reset"
235
+ },
236
+ {
237
+ "present_tense": "Reversing polarity of neutron flow",
238
+ "past_tense": "Reversed"
239
+ },
240
+ {
241
+ "present_tense": "Rewinding timeline",
242
+ "past_tense": "Rewound"
243
+ },
244
+ {
245
+ "present_tense": "Rewiring TARDIS console",
246
+ "past_tense": "Rewired"
247
+ },
248
+ {
249
+ "present_tense": "Saving Gallifrey",
250
+ "past_tense": "Saved"
251
+ },
252
+ {
253
+ "present_tense": "Setting coordinates for Gallifrey",
254
+ "past_tense": "Set"
255
+ },
256
+ {
257
+ "present_tense": "Snapping fingers to open TARDIS",
258
+ "past_tense": "Snapped"
259
+ },
260
+ {
261
+ "present_tense": "Speaking baby",
262
+ "past_tense": "Spoke"
263
+ },
264
+ {
265
+ "present_tense": "Straightening bow tie",
266
+ "past_tense": "Straightened"
267
+ },
268
+ {
269
+ "present_tense": "Waving sonic screwdriver",
270
+ "past_tense": "Waved"
271
+ },
272
+ {
273
+ "present_tense": "Wearing celery",
274
+ "past_tense": "Wore"
275
+ },
276
+ {
277
+ "present_tense": "Whacking console with mallet",
278
+ "past_tense": "Whacked"
279
+ }
280
+ ]
281
+ }
282
+ ]
283
+ }
@@ -0,0 +1,135 @@
1
+ {
2
+ "packs": [
3
+ {
4
+ "id": "firefly",
5
+ "name": "Firefly",
6
+ "description": "Independent crew running jobs on the raggedy edge.",
7
+ "words": [
8
+ {
9
+ "present_tense": "Accepting payment in chickens",
10
+ "past_tense": "Accepted"
11
+ },
12
+ {
13
+ "present_tense": "Aiming to misbehave",
14
+ "past_tense": "Aimed"
15
+ },
16
+ {
17
+ "present_tense": "Avoiding Reavers",
18
+ "past_tense": "Avoided"
19
+ },
20
+ {
21
+ "present_tense": "Bringing Vera",
22
+ "past_tense": "Brought"
23
+ },
24
+ {
25
+ "present_tense": "Coaxing ailing engines",
26
+ "past_tense": "Coaxed"
27
+ },
28
+ {
29
+ "present_tense": "Cursing sudden inevitable betrayal",
30
+ "past_tense": "Cursed"
31
+ },
32
+ {
33
+ "present_tense": "Debating theology with Book",
34
+ "past_tense": "Debated"
35
+ },
36
+ {
37
+ "present_tense": "Docking at Persephone",
38
+ "past_tense": "Docked"
39
+ },
40
+ {
41
+ "present_tense": "Evading Alliance patrols",
42
+ "past_tense": "Evaded"
43
+ },
44
+ {
45
+ "present_tense": "Executing crazy Ivan",
46
+ "past_tense": "Executed"
47
+ },
48
+ {
49
+ "present_tense": "Fighting losing war",
50
+ "past_tense": "Fought"
51
+ },
52
+ {
53
+ "present_tense": "Fleeing blue-gloved agents",
54
+ "past_tense": "Fled"
55
+ },
56
+ {
57
+ "present_tense": "Haggling with clients",
58
+ "past_tense": "Haggled"
59
+ },
60
+ {
61
+ "present_tense": "Inspiring folk ballads",
62
+ "past_tense": "Inspired"
63
+ },
64
+ {
65
+ "present_tense": "Judging stranger's hat",
66
+ "past_tense": "Judged"
67
+ },
68
+ {
69
+ "present_tense": "Keeping flying",
70
+ "past_tense": "Kept"
71
+ },
72
+ {
73
+ "present_tense": "Negotiating with Niska",
74
+ "past_tense": "Negotiated"
75
+ },
76
+ {
77
+ "present_tense": "Opting for thrilling heroics",
78
+ "past_tense": "Opted"
79
+ },
80
+ {
81
+ "present_tense": "Performing big damn rescue",
82
+ "past_tense": "Performed"
83
+ },
84
+ {
85
+ "present_tense": "Playing dinosaur games",
86
+ "past_tense": "Played"
87
+ },
88
+ {
89
+ "present_tense": "Reading minds unexpectedly",
90
+ "past_tense": "Read"
91
+ },
92
+ {
93
+ "present_tense": "Retreating to bunk",
94
+ "past_tense": "Retreated"
95
+ },
96
+ {
97
+ "present_tense": "Smuggling goods past customs",
98
+ "past_tense": "Smuggled"
99
+ },
100
+ {
101
+ "present_tense": "Soaring like leaf on wind",
102
+ "past_tense": "Soared"
103
+ },
104
+ {
105
+ "present_tense": "Splitting thin profits",
106
+ "past_tense": "Split"
107
+ },
108
+ {
109
+ "present_tense": "Staying shiny",
110
+ "past_tense": "Stayed"
111
+ },
112
+ {
113
+ "present_tense": "Stealing medicine from train",
114
+ "past_tense": "Stole"
115
+ },
116
+ {
117
+ "present_tense": "Swearing in Mandarin",
118
+ "past_tense": "Swore"
119
+ },
120
+ {
121
+ "present_tense": "Taking passengers",
122
+ "past_tense": "Took"
123
+ },
124
+ {
125
+ "present_tense": "Warning about special hell",
126
+ "past_tense": "Warned"
127
+ },
128
+ {
129
+ "present_tense": "Wearing browncoat proudly",
130
+ "past_tense": "Wore"
131
+ }
132
+ ]
133
+ }
134
+ ]
135
+ }