pi-spark 0.22.2 → 0.22.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/CHANGELOG.md ADDED
@@ -0,0 +1,527 @@
1
+ # Changelog
2
+
3
+ ## [0.22.3](https://github.com/zlliang/pi-spark/compare/v0.22.2...v0.22.3) (2026-09-10)
4
+
5
+
6
+ ### Features
7
+
8
+ * **credits:** add provider dashboard hyperlinks ([f7a7ec2](https://github.com/zlliang/pi-spark/commit/f7a7ec2b2394dd65e5c6ce20bc4b3d8fb5cc600e))
9
+ * **credits:** show reset times and convert Kimi balances to USD ([7c4a478](https://github.com/zlliang/pi-spark/commit/7c4a4782cecba8ecc557bfcf496b898347b5e2b5))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * correct cache probe config typing ([1695212](https://github.com/zlliang/pi-spark/commit/1695212c607163ebc2fbb721d6088377f36b9887))
15
+ * **credits:** update Codex usage settings link ([4f8d72c](https://github.com/zlliang/pi-spark/commit/4f8d72c6acbd519ab7850b8a086a09de5d83ca98))
16
+
17
+ ## [0.22.2](https://github.com/zlliang/pi-spark/compare/v0.22.1...v0.22.2) (2026-09-04)
18
+
19
+
20
+ ### Miscellaneous Chores
21
+
22
+ * trigger release 0.22.2 ([b8463a8](https://github.com/zlliang/pi-spark/commit/b8463a887b9be6c81d8d55df7b6a31df6acdb21f))
23
+
24
+ ## [0.22.1](https://github.com/zlliang/pi-spark/compare/v0.22.0...v0.22.1) (2026-09-04)
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * **auth:** pass environment to background requests ([a89c943](https://github.com/zlliang/pi-spark/commit/a89c943c4190b659ac4cf3ffec49eff315008f94))
30
+ * **credits:** enable credits status in RPC mode ([#72](https://github.com/zlliang/pi-spark/issues/72)) ([58e9cc1](https://github.com/zlliang/pi-spark/commit/58e9cc16bbae4a06cc9ea89e694f7723f6abcd7d))
31
+ * **credits:** simplify mode check ([a58acd1](https://github.com/zlliang/pi-spark/commit/a58acd1ca7830f4a03941ad90778a1b4f2ae715c))
32
+ * **model:** avoid authenticating fallback models ([3a6f6a1](https://github.com/zlliang/pi-spark/commit/3a6f6a12bbf180079cf09333842cf4159583cf7e))
33
+
34
+ ## [0.22.0](https://github.com/zlliang/pi-spark/compare/v0.21.1...v0.22.0) (2026-08-07)
35
+
36
+
37
+ ### ⚠ BREAKING CHANGES
38
+
39
+ * **fullscreen:** use Pi's native fullscreen mode
40
+
41
+ ### Code Refactoring
42
+
43
+ * **fullscreen:** use Pi's native fullscreen mode ([3fbc092](https://github.com/zlliang/pi-spark/commit/3fbc09234f4baff627624b99714fd8057e179e80))
44
+
45
+ ## [0.21.1](https://github.com/zlliang/pi-spark/compare/v0.21.0...v0.21.1) (2026-07-24)
46
+
47
+
48
+ ### Bug Fixes
49
+
50
+ * **credits:** extract token from Authorization header for OAuth providers ([06f7309](https://github.com/zlliang/pi-spark/commit/06f7309bd520e76947dc7a9523b6fc4e2855a779))
51
+ * **credits:** resolve OAuth tokens consistently ([e7fd9d8](https://github.com/zlliang/pi-spark/commit/e7fd9d8098cfaf96c79a7122b95d388016b6cefa))
52
+ * **presets:** skip unavailable presets when cycling ([72348da](https://github.com/zlliang/pi-spark/commit/72348da41a6037165a1d89381a98fa54e8209993))
53
+
54
+ ## [0.21.0](https://github.com/zlliang/pi-spark/compare/v0.20.0...v0.21.0) (2026-07-23)
55
+
56
+
57
+ ### Features
58
+
59
+ * **credits:** retry HTTP requests with Ky ([ee0a304](https://github.com/zlliang/pi-spark/commit/ee0a304de314a7950e9289ea2cb1618caf4d67bb))
60
+ * **editor:** add model thinking level indicator ([d27059d](https://github.com/zlliang/pi-spark/commit/d27059df79f77d4087fe5c20218e3f76385781ae))
61
+ * **themes:** add GitHub default themes ([40838ed](https://github.com/zlliang/pi-spark/commit/40838ed1b00be8b66da335eb8d29fa059b0bf51b))
62
+ * **write:** add scrolling tail previews ([7542dde](https://github.com/zlliang/pi-spark/commit/7542dde92ac0c3973f9b284001d530b4115ff21c))
63
+
64
+
65
+ ### Bug Fixes
66
+
67
+ * **footer:** include all session usage costs ([ed69b31](https://github.com/zlliang/pi-spark/commit/ed69b314bd1d56072b55804f64b7ed0f738675d8))
68
+ * **modes:** handle non-TUI sessions correctly ([58e0246](https://github.com/zlliang/pi-spark/commit/58e02460109ca2cb494bc870ef1b8be0d2140e4f))
69
+ * **themes:** improve muted colors and code fence contrast ([b8a85d9](https://github.com/zlliang/pi-spark/commit/b8a85d96cec879c59cfc2d3eb9aeee0f6b4efb72))
70
+ * **title:** generate after first turn ([5fbf21e](https://github.com/zlliang/pi-spark/commit/5fbf21e0c2a2489d0582171a3b763dba045f1189))
71
+ * **write:** clarify omitted line summary ([702af59](https://github.com/zlliang/pi-spark/commit/702af59c5877147a05c4279b80e7258807a837c6))
72
+
73
+
74
+ ### Performance Improvements
75
+
76
+ * **fullscreen:** render transcript only once ([7eb60b9](https://github.com/zlliang/pi-spark/commit/7eb60b960d7acc544a8f5aa18b935f12c4bd9457))
77
+
78
+ ## [0.20.0](https://github.com/zlliang/pi-spark/compare/v0.19.3...v0.20.0) (2026-07-19)
79
+
80
+
81
+ ### Features
82
+
83
+ * **credits:** add per-provider enable/disable config ([ec800ef](https://github.com/zlliang/pi-spark/commit/ec800ef0cc44abcfebb0f54577c648c2ab8f3a86))
84
+ * **credits:** improve Kimi usage reporting ([675d5f0](https://github.com/zlliang/pi-spark/commit/675d5f077e9cb16e491d25e243f5641fc11861b1))
85
+ * **footer:** add statusPosition config for inline/below extension statuses ([4bfec49](https://github.com/zlliang/pi-spark/commit/4bfec49c7bbe656404dd75f2e335939f3ec88d8c))
86
+
87
+
88
+ ### Bug Fixes
89
+
90
+ * **credits:** clarify Kimi extra usage balance ([685052c](https://github.com/zlliang/pi-spark/commit/685052c1e04e1ffbfdecd876305eb00f08dacb97))
91
+ * **fullscreen:** suppress idle status gap ([02cc41d](https://github.com/zlliang/pi-spark/commit/02cc41d522512b3c5fdf2111032f1d1d8b07ce56))
92
+
93
+ ## [0.19.3](https://github.com/zlliang/pi-spark/compare/v0.19.2...v0.19.3) (2026-07-17)
94
+
95
+
96
+ ### Bug Fixes
97
+
98
+ * **credits:** handle missing used value in Kimi Code lane ([5eb86f8](https://github.com/zlliang/pi-spark/commit/5eb86f8f0606ef88e0adda73b65e2ec29b9ae57d))
99
+ * **footer:** hide cost below half a cent ([04c0f17](https://github.com/zlliang/pi-spark/commit/04c0f17f07ba6400b7a37d797b1d02dd7faf7c06))
100
+
101
+ ## [0.19.2](https://github.com/zlliang/pi-spark/compare/v0.19.1...v0.19.2) (2026-07-17)
102
+
103
+
104
+ ### Bug Fixes
105
+
106
+ * support Pi 0.80.8 ([3f786a1](https://github.com/zlliang/pi-spark/commit/3f786a1db1c60ceb9a4563cab34e35ca55dba232))
107
+
108
+ ## [0.19.1](https://github.com/zlliang/pi-spark/compare/v0.19.0...v0.19.1) (2026-07-13)
109
+
110
+
111
+ ### Bug Fixes
112
+
113
+ * **credits:** derive Codex window labels from limits ([65e7900](https://github.com/zlliang/pi-spark/commit/65e7900a22803c9e0db18837100bb11c6557a617))
114
+
115
+ ## [0.19.0](https://github.com/zlliang/pi-spark/compare/v0.18.1...v0.19.0) (2026-07-11)
116
+
117
+
118
+ ### Features
119
+
120
+ * **credits:** add Codex reset redemption ([1c56eea](https://github.com/zlliang/pi-spark/commit/1c56eeae9fb3ed46f859fbe8c88e8ce78a388950))
121
+
122
+
123
+ ### Bug Fixes
124
+
125
+ * **lifecycle:** wait for agent settlement ([7653b51](https://github.com/zlliang/pi-spark/commit/7653b513f8b6a91354fa1ba70f688639b142a206))
126
+ * **package:** include docs in published files ([14d96f9](https://github.com/zlliang/pi-spark/commit/14d96f9b5cb1aefda7d5d06ee9fb0cd3ccdf8d62))
127
+ * **title:** use sentence case for English titles ([747e41d](https://github.com/zlliang/pi-spark/commit/747e41db088ba80d617363e8f237f2ad505292a5))
128
+
129
+ ## [0.18.1](https://github.com/zlliang/pi-spark/compare/v0.18.0...v0.18.1) (2026-07-10)
130
+
131
+
132
+ ### Bug Fixes
133
+
134
+ * **lockfile:** normalize pi-ai binary path ([9d9a641](https://github.com/zlliang/pi-spark/commit/9d9a64155105b114f1d6f3576622144ab18505fc))
135
+ * **model:** isolate background Codex sessions ([b240e53](https://github.com/zlliang/pi-spark/commit/b240e53672ef452ea17b962fb683a552c5ca3904))
136
+
137
+ ## [0.18.0](https://github.com/zlliang/pi-spark/compare/v0.17.1...v0.18.0) (2026-07-10)
138
+
139
+
140
+ ### Features
141
+
142
+ * **config:** support max thinking level ([3d58e28](https://github.com/zlliang/pi-spark/commit/3d58e28a5da00c95a33bc5735b8f8e0bb1b66fad))
143
+
144
+ ## [0.17.1](https://github.com/zlliang/pi-spark/compare/v0.17.0...v0.17.1) (2026-07-10)
145
+
146
+
147
+ ### Bug Fixes
148
+
149
+ * preserve routing for background model calls ([27b2c12](https://github.com/zlliang/pi-spark/commit/27b2c12f3d3c179dca4ce44978a34725d6f4db60))
150
+
151
+ ## [0.17.0](https://github.com/zlliang/pi-spark/compare/v0.16.0...v0.17.0) (2026-07-09)
152
+
153
+
154
+ ### Features
155
+
156
+ * add kimi code provider ([#56](https://github.com/zlliang/pi-spark/issues/56)) ([8950df3](https://github.com/zlliang/pi-spark/commit/8950df3c8ac58158a817d7e4cc8a26d315c5a534))
157
+
158
+
159
+ ### Bug Fixes
160
+
161
+ * **credits:** always show Kimi Code weekly usage lane ([985ba89](https://github.com/zlliang/pi-spark/commit/985ba8974fa07490941c7eb77a076ace20566d1f)), closes [#56](https://github.com/zlliang/pi-spark/issues/56)
162
+ * **credits:** fix Kimi Code weekly lane always rendering ([76e9227](https://github.com/zlliang/pi-spark/commit/76e922751d09e81f3619f4493c895306c255c34d)), closes [#56](https://github.com/zlliang/pi-spark/issues/56)
163
+
164
+ ## [0.16.0](https://github.com/zlliang/pi-spark/compare/v0.15.0...v0.16.0) (2026-07-09)
165
+
166
+
167
+ ### Features
168
+
169
+ * **title:** name sessions automatically after the first exchange ([dcef9f5](https://github.com/zlliang/pi-spark/commit/dcef9f5a9d71d6f793383526dfb3d924d0937d93))
170
+
171
+
172
+ ### Bug Fixes
173
+
174
+ * **presets:** use border color for preset selector border ([500a868](https://github.com/zlliang/pi-spark/commit/500a8681758533433e8d6da6d0eafa5c9774d141))
175
+ * update pi-ai provider imports ([ccf7f6d](https://github.com/zlliang/pi-spark/commit/ccf7f6dc292c0c11f114f19a48f3b72f58016345))
176
+
177
+ ## [0.15.0](https://github.com/zlliang/pi-spark/compare/v0.14.7...v0.15.0) (2026-06-20)
178
+
179
+
180
+ ### Features
181
+
182
+ * **footer:** hide cost display for free models when cost is zero ([78e0a23](https://github.com/zlliang/pi-spark/commit/78e0a230d6a148b927d5cd598c0edee505c260c2))
183
+ * remove pi and web agent tools ([1acb837](https://github.com/zlliang/pi-spark/commit/1acb8377bbad437a31d8feb91112529f332964ab))
184
+
185
+
186
+ ### Bug Fixes
187
+
188
+ * **config:** use shared config directory name ([bc5dae0](https://github.com/zlliang/pi-spark/commit/bc5dae08d8528a41e379c041cf0eaba2b176ae68))
189
+ * **tool:** handle missing composed tool action ([e93bf39](https://github.com/zlliang/pi-spark/commit/e93bf391c26afad3e8bf84123d26f1f2a9626a60))
190
+
191
+ ## [0.14.7](https://github.com/zlliang/pi-spark/compare/v0.14.6...v0.14.7) (2026-06-17)
192
+
193
+
194
+ ### Bug Fixes
195
+
196
+ * **config:** isolate invalid feature config instead of disabling all ([c57addb](https://github.com/zlliang/pi-spark/commit/c57addb510ce88031c7def2ddde97a594ac1f39f))
197
+ * **credits:** cancel inflight request on session shutdown ([2695273](https://github.com/zlliang/pi-spark/commit/2695273e155da4aa1edd87098c3574363833aad0))
198
+
199
+ ## [0.14.6](https://github.com/zlliang/pi-spark/compare/v0.14.5...v0.14.6) (2026-06-15)
200
+
201
+
202
+ ### Bug Fixes
203
+
204
+ * **pi:** trim name parameters and align state output ([2dd5efc](https://github.com/zlliang/pi-spark/commit/2dd5efc9888763399a8af4e6d96d5d7744959daa))
205
+ * **presets:** apply preset flag only on startup ([b0a2585](https://github.com/zlliang/pi-spark/commit/b0a2585a6fa63b3a72b14daf2802ad90eace1a3c))
206
+ * **presets:** improve selector layout and key hints ([9bf0c9f](https://github.com/zlliang/pi-spark/commit/9bf0c9f7b5f00dda84464fe8327054af00a9d26b))
207
+ * **utils:** prevent duplicate elapsed timing line in composed tools ([0a00fd5](https://github.com/zlliang/pi-spark/commit/0a00fd554c7eeadeb099f185507e63a850dd89c6))
208
+
209
+ ## [0.14.5](https://github.com/zlliang/pi-spark/compare/v0.14.4...v0.14.5) (2026-06-14)
210
+
211
+
212
+ ### Bug Fixes
213
+
214
+ * **startup:** defer heavy gRPC and MCP imports to first use ([2080906](https://github.com/zlliang/pi-spark/commit/2080906515452d3ad4464b6cf2892dc765025458))
215
+
216
+ ## [0.14.4](https://github.com/zlliang/pi-spark/compare/v0.14.3...v0.14.4) (2026-06-14)
217
+
218
+
219
+ ### Features
220
+
221
+ * **tools:** add per-action execution timing to composed tools ([b857f1d](https://github.com/zlliang/pi-spark/commit/b857f1d8ccd1b5b5713c3486291889b7d037e298))
222
+
223
+ ## [0.14.3](https://github.com/zlliang/pi-spark/compare/v0.14.2...v0.14.3) (2026-06-14)
224
+
225
+
226
+ ### Code Refactoring
227
+
228
+ * **tools:** share composed-tool architecture across pi and web ([12e563b](https://github.com/zlliang/pi-spark/commit/12e563b357f9e5cf83fef04943c66feffd16c26f))
229
+
230
+ ## [0.14.2](https://github.com/zlliang/pi-spark/compare/v0.14.1...v0.14.2) (2026-06-14)
231
+
232
+
233
+ ### Bug Fixes
234
+
235
+ * **pi:** simplify missing model display ([ab6389e](https://github.com/zlliang/pi-spark/commit/ab6389ea0e8e13360c221d6b9fc450e80514416d))
236
+
237
+ ## [0.14.1](https://github.com/zlliang/pi-spark/compare/v0.14.0...v0.14.1) (2026-06-14)
238
+
239
+
240
+ ### Miscellaneous Chores
241
+
242
+ * trigger release 0.14.1 ([b966f0e](https://github.com/zlliang/pi-spark/commit/b966f0ecb4739cbf250051de652fc0f51fa9d5f9))
243
+
244
+ ## [0.14.0](https://github.com/zlliang/pi-spark/compare/v0.13.1...v0.14.0) (2026-06-14)
245
+
246
+
247
+ ### Features
248
+
249
+ * add unified pi and web agent tools ([1229d93](https://github.com/zlliang/pi-spark/commit/1229d93e1beffd444767781c3c1332e26706dc8a))
250
+
251
+ ## [0.13.1](https://github.com/zlliang/pi-spark/compare/v0.13.0...v0.13.1) (2026-06-14)
252
+
253
+
254
+ ### Documentation
255
+
256
+ * refresh README screenshots ([85948f7](https://github.com/zlliang/pi-spark/commit/85948f763b7fdcdf6020f17ebc425398a3133bc9))
257
+
258
+ ## [0.13.0](https://github.com/zlliang/pi-spark/compare/v0.12.0...v0.13.0) (2026-06-14)
259
+
260
+
261
+ ### Code Refactoring
262
+
263
+ * consolidate features into a single extension ([5fd0f5c](https://github.com/zlliang/pi-spark/commit/5fd0f5c5a577fe0808a91b4d313a1cd569e9288f))
264
+
265
+ ## [0.12.0](https://github.com/zlliang/pi-spark/compare/v0.11.2...v0.12.0) (2026-06-13)
266
+
267
+
268
+ ### ⚠ BREAKING CHANGES
269
+
270
+ * fold pi-credits into pi-spark and revert to single package
271
+
272
+ ### Miscellaneous Chores
273
+
274
+ * release 0.12.0 ([e80081a](https://github.com/zlliang/pi-spark/commit/e80081a2d352da108feea446d44fb63f9ecc68ff))
275
+
276
+
277
+ ### Code Refactoring
278
+
279
+ * fold pi-credits into pi-spark and revert to single package ([3a1cbe3](https://github.com/zlliang/pi-spark/commit/3a1cbe360feeab02a1d8b8313eaf6b06b4f8d400))
280
+
281
+ ## [0.11.2](https://github.com/zlliang/pi-spark/compare/v0.11.1...v0.11.2) (2026-06-13)
282
+
283
+
284
+ ### Documentation
285
+
286
+ * **pi-spark:** simplify description ([ede2299](https://github.com/zlliang/pi-spark/commit/ede2299cee377401c066bd76d8e795c9f96d4f1d))
287
+
288
+ ## [0.11.1](https://github.com/zlliang/pi-spark/compare/v0.11.0...v0.11.1) (2026-06-13)
289
+
290
+
291
+ ### Documentation
292
+
293
+ * **pi-spark:** polish README and metadata ([382de1a](https://github.com/zlliang/pi-spark/commit/382de1aeaa48de7d874d088cba60b6ff1e60d42d))
294
+
295
+ ## [0.11.0](https://github.com/zlliang/pi-spark/compare/v0.10.5...v0.11.0) (2026-06-13)
296
+
297
+
298
+ ### Miscellaneous Chores
299
+
300
+ * **pi-spark:** release 0.11.0 ([c5124d4](https://github.com/zlliang/pi-spark/commit/c5124d4070c7caa96e0e1fc37e0a23b45232e38c))
301
+
302
+ ## [0.10.5](https://github.com/zlliang/pi-spark/compare/v0.10.4...v0.10.5) (2026-06-13)
303
+
304
+
305
+ ### Bug Fixes
306
+
307
+ * **pi-spark:** reassert clearOnShrink each render in fullscreen ([55604b5](https://github.com/zlliang/pi-spark/commit/55604b59742b5300ef80102f9fbc3fc1c7a798cd))
308
+
309
+ ## [0.10.4](https://github.com/zlliang/pi-spark/compare/v0.10.3...v0.10.4) (2026-06-13)
310
+
311
+
312
+ ### Bug Fixes
313
+
314
+ * add npm package homepage metadata ([9ff2e39](https://github.com/zlliang/pi-spark/commit/9ff2e39d609c3c0a39c45a6c6b456bde964fbaa8))
315
+
316
+ ## [0.10.3](https://github.com/zlliang/pi-spark/compare/v0.10.2...v0.10.3) (2026-06-13)
317
+
318
+
319
+ ### Miscellaneous Chores
320
+
321
+ * **pi-spark:** release 0.10.3 ([c253364](https://github.com/zlliang/pi-spark/commit/c2533641a4c9fe3b91ad6d0a52077d65036a95f0))
322
+
323
+ ## [0.10.2](https://github.com/zlliang/pi-spark/compare/v0.10.1...v0.10.2) (2026-06-13)
324
+
325
+
326
+ ### Bug Fixes
327
+
328
+ * simplify cost display ([4990a57](https://github.com/zlliang/pi-spark/commit/4990a57fd9688929e115d64121a009630988d93e))
329
+
330
+ ## [0.10.1](https://github.com/zlliang/pi-spark/compare/v0.10.0...v0.10.1) (2026-06-13)
331
+
332
+
333
+ ### Miscellaneous Chores
334
+
335
+ * bump to 0.10.1 ([14a7b3d](https://github.com/zlliang/pi-spark/commit/14a7b3dc56d329095e478d0e0e1979a177bb1cfe))
336
+
337
+ ## [0.10.0](https://github.com/zlliang/pi-spark/compare/v0.9.5...v0.10.0) (2026-06-13)
338
+
339
+
340
+ ### ⚠ BREAKING CHANGES
341
+
342
+ * **models:** the model tool's "current" action is renamed to "active", and the scope/provider/model params are replaced by "query".
343
+
344
+ ### Features
345
+
346
+ * **models:** filter model lists with Liqe queries ([877479b](https://github.com/zlliang/pi-spark/commit/877479b51a715b7a5a05381b207ecd03837e433d))
347
+
348
+
349
+ ### Styles
350
+
351
+ * **name:** use complete sentences in tool prose ([3430899](https://github.com/zlliang/pi-spark/commit/343089946f685b70c1bcda0291cf511f536a0711))
352
+
353
+ ## [0.9.5](https://github.com/zlliang/pi-spark/compare/v0.9.4...v0.9.5) (2026-06-12)
354
+
355
+
356
+ ### Bug Fixes
357
+
358
+ * **models:** keep unavailable model labels visible ([feab815](https://github.com/zlliang/pi-spark/commit/feab8159210033ad362a4951e835247e28325063))
359
+
360
+ ## [0.9.4](https://github.com/zlliang/pi-spark/compare/v0.9.3...v0.9.4) (2026-06-12)
361
+
362
+
363
+ ### Bug Fixes
364
+
365
+ * **models:** expose unavailable models by scope ([8df5053](https://github.com/zlliang/pi-spark/commit/8df5053b1b92aaa78a366088b9414e7f197c4072))
366
+
367
+ ## [0.9.3](https://github.com/zlliang/pi-spark/compare/v0.9.2...v0.9.3) (2026-06-12)
368
+
369
+
370
+ ### Bug Fixes
371
+
372
+ * **models:** align action description order ([3de17c1](https://github.com/zlliang/pi-spark/commit/3de17c1d5f341eeb8673c70060a8dcb8febe8f5c))
373
+ * update model and name extension exports ([68b5191](https://github.com/zlliang/pi-spark/commit/68b51916c89717ac26ccafb863d420d16dd0423c))
374
+
375
+ ## [0.9.2](https://github.com/zlliang/pi-spark/compare/v0.9.1...v0.9.2) (2026-06-12)
376
+
377
+
378
+ ### Bug Fixes
379
+
380
+ * **models:** show expand hint in model tool call ([a7ac029](https://github.com/zlliang/pi-spark/commit/a7ac02943e0621e04093c5cc0a81a192fe440801))
381
+
382
+ ## [0.9.1](https://github.com/zlliang/pi-spark/compare/v0.9.0...v0.9.1) (2026-06-12)
383
+
384
+
385
+ ### Bug Fixes
386
+
387
+ * **models:** polish model tool prompt guideline ([eb01e6b](https://github.com/zlliang/pi-spark/commit/eb01e6b5a3b5dd180d32b9a9c8e06e4b90f42036))
388
+
389
+ ## [0.9.0](https://github.com/zlliang/pi-spark/compare/v0.8.0...v0.9.0) (2026-06-12)
390
+
391
+
392
+ ### Features
393
+
394
+ * **models:** add model inspection tool ([4d2625e](https://github.com/zlliang/pi-spark/commit/4d2625e2e2bd2e5637c50e563efff7b271a5a21d))
395
+
396
+ ## [0.8.0](https://github.com/zlliang/pi-spark/compare/v0.7.0...v0.8.0) (2026-06-10)
397
+
398
+
399
+ ### Features
400
+
401
+ * **credits:** generalize codex-usage into multi-provider credits ([84ffc8e](https://github.com/zlliang/pi-spark/commit/84ffc8e25256619a6b82759095be554433de15d0))
402
+ * move credits extension to the dedicated pi-credits package ([2d1e868](https://github.com/zlliang/pi-spark/commit/2d1e868f2c541c3707c9564ccdedaf80f40a7be5))
403
+
404
+ ## [0.7.0](https://github.com/zlliang/pi-spark/compare/v0.6.3...v0.7.0) (2026-06-10)
405
+
406
+
407
+ ### Code Refactoring
408
+
409
+ * remove trust-all extension ([2a783f9](https://github.com/zlliang/pi-spark/commit/2a783f9d3aa3031f0c204b047546c8f5d1aa6728))
410
+
411
+ ## [0.6.3](https://github.com/zlliang/pi-spark/compare/v0.6.2...v0.6.3) (2026-06-09)
412
+
413
+
414
+ ### Code Refactoring
415
+
416
+ * rename session naming tool ([49f8502](https://github.com/zlliang/pi-spark/commit/49f850226a175e280b0337f96fbaa649276d1153))
417
+
418
+ ## [0.6.2](https://github.com/zlliang/pi-spark/compare/v0.6.1...v0.6.2) (2026-06-09)
419
+
420
+
421
+ ### Code Refactoring
422
+
423
+ * adjust set-session-name reason handling ([6d1b0b8](https://github.com/zlliang/pi-spark/commit/6d1b0b8ba3859b0a8b991758f01582caf65d6c8c))
424
+
425
+ ## [0.6.1](https://github.com/zlliang/pi-spark/compare/v0.6.0...v0.6.1) (2026-06-09)
426
+
427
+
428
+ ### Code Refactoring
429
+
430
+ * **editor:** show preset name in bold without prefix ([79a5fe2](https://github.com/zlliang/pi-spark/commit/79a5fe2910647094503bca9ccbc69326c6ade12a))
431
+
432
+ ## [0.6.0](https://github.com/zlliang/pi-spark/compare/v0.5.2...v0.6.0) (2026-06-09)
433
+
434
+
435
+ ### Features
436
+
437
+ * add trust-all extension ([2784e47](https://github.com/zlliang/pi-spark/commit/2784e4719689280029864c45455bdac1d515669a))
438
+ * **codex-usage:** refresh after usage events ([bc53364](https://github.com/zlliang/pi-spark/commit/bc533646d085966376278ec6672b7d51d11c3e2d))
439
+ * **editor:** add pulse spinner preset ([9033de9](https://github.com/zlliang/pi-spark/commit/9033de9552630b16481dcb37aa9556bd37ab1bc7))
440
+
441
+ ## [0.5.2](https://github.com/zlliang/pi-spark/compare/v0.5.1...v0.5.2) (2026-06-08)
442
+
443
+
444
+ ### Bug Fixes
445
+
446
+ * **codex-usage:** round status percentages ([a641329](https://github.com/zlliang/pi-spark/commit/a64132919bd99d67d2dd039206ab80a41cfab720))
447
+
448
+ ## [0.5.1](https://github.com/zlliang/pi-spark/compare/v0.5.0...v0.5.1) (2026-06-08)
449
+
450
+
451
+ ### Bug Fixes
452
+
453
+ * **codex-usage:** polish usage error message ([99edccf](https://github.com/zlliang/pi-spark/commit/99edccf6d19b3fdb334414b46f59a25d542bc03d))
454
+
455
+ ## [0.5.0](https://github.com/zlliang/pi-spark/compare/v0.4.0...v0.5.0) (2026-06-08)
456
+
457
+
458
+ ### Features
459
+
460
+ * **codex-usage:** add Codex rate-limit usage status ([6778581](https://github.com/zlliang/pi-spark/commit/67785818e3cb2304b16b1feaf1dfb58520cb1542))
461
+
462
+ ## [0.4.0](https://github.com/zlliang/pi-spark/compare/v0.3.1...v0.4.0) (2026-06-08)
463
+
464
+
465
+ ### Features
466
+
467
+ * **set-session-name:** add session naming tool ([bc60e90](https://github.com/zlliang/pi-spark/commit/bc60e9049e17e1b82fc0d936731235f2bd4e94dd))
468
+
469
+ ## [0.3.1](https://github.com/zlliang/pi-spark/compare/v0.3.0...v0.3.1) (2026-06-08)
470
+
471
+
472
+ ### Bug Fixes
473
+
474
+ * **fullscreen:** keep clearOnShrink enabled across reload ([e1adde0](https://github.com/zlliang/pi-spark/commit/e1adde0eca052319dd9231f6e22456ae33109289))
475
+
476
+ ## [0.3.0](https://github.com/zlliang/pi-spark/compare/v0.2.1...v0.3.0) (2026-06-06)
477
+
478
+
479
+ ### Features
480
+
481
+ * **footer:** shorten cwd display ([8ae3525](https://github.com/zlliang/pi-spark/commit/8ae3525af6311de94c4b85f07e3f9c6df5369011))
482
+ * **fullscreen:** clear session on exit ([b48b997](https://github.com/zlliang/pi-spark/commit/b48b9972365da5c24d2f90f36d1ba0e945d87e94))
483
+
484
+
485
+ ### Bug Fixes
486
+
487
+ * **fullscreen:** style exit session label ([b7fcd80](https://github.com/zlliang/pi-spark/commit/b7fcd80113e52efd6c46bcd617c3c0520fcb2fb0))
488
+
489
+ ## [0.2.1](https://github.com/zlliang/pi-spark/compare/v0.2.0...v0.2.1) (2026-06-04)
490
+
491
+
492
+ ### Miscellaneous Chores
493
+
494
+ * release 0.2.1 ([d296d5d](https://github.com/zlliang/pi-spark/commit/d296d5de0eb890b1f9c10dd5edd7343224a58819))
495
+
496
+ ## [0.2.0](https://github.com/zlliang/pi-spark/compare/v0.1.2...v0.2.0) (2026-06-04)
497
+
498
+
499
+ ### Features
500
+
501
+ * **editor:** show working status in border ([b72b127](https://github.com/zlliang/pi-spark/commit/b72b12738b209bb3016009c88e2efd1544d770f6))
502
+ * **footer:** include statuses in main line ([93a18de](https://github.com/zlliang/pi-spark/commit/93a18de6fbd53e7751dbecb01f9efa7b954d8bdf))
503
+ * **presets:** support preset CLI flag ([435c164](https://github.com/zlliang/pi-spark/commit/435c164b61ce231074fdbdee636d45af1845bebf))
504
+
505
+
506
+ ### Bug Fixes
507
+
508
+ * **editor:** clear tool status after executions ([780395f](https://github.com/zlliang/pi-spark/commit/780395f79e078dd7c4af596f5dd66b344ce3ef34))
509
+ * **editor:** track running tools by call id ([72fbe37](https://github.com/zlliang/pi-spark/commit/72fbe370995296988bcd3100d2c25721b08af62b))
510
+
511
+ ## [0.1.2](https://github.com/zlliang/pi-spark/compare/v0.1.1...v0.1.2) (2026-06-03)
512
+
513
+
514
+ ### Bug Fixes
515
+
516
+ * **editor:** add tildes spinner preset ([523f6fc](https://github.com/zlliang/pi-spark/commit/523f6fcd982455fbfe202982c5dfb7a62590b6dd))
517
+
518
+ ## [0.1.1](https://github.com/zlliang/pi-spark/compare/v0.1.0...v0.1.1) (2026-06-02)
519
+
520
+
521
+ ### Miscellaneous Chores
522
+
523
+ * release 0.1.1 ([09bfd96](https://github.com/zlliang/pi-spark/commit/09bfd96eec21dc9467bbbf10946bc5bb9cf858f7))
524
+
525
+ ## [0.1.0](https://github.com/zlliang/pi-spark/releases/tag/v0.1.0) (2026-06-02)
526
+
527
+ Initial release of pi-spark, including the Editor, Footer, Fullscreen, Presets, and Recap extensions, plus shared TUI components and spark configuration support.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-spark",
3
- "version": "0.22.2",
3
+ "version": "0.22.3",
4
4
  "description": "Pi package that polishes your daily experience",
5
5
  "keywords": [
6
6
  "pi-coding-agent",
@@ -13,13 +13,14 @@
13
13
  "license": "MIT",
14
14
  "type": "module",
15
15
  "files": [
16
- "index.ts",
17
- "src",
18
- "themes",
19
16
  "assets",
20
17
  "docs",
21
- "README.md",
22
- "LICENSE"
18
+ "src",
19
+ "themes",
20
+ "CHANGELOG.md",
21
+ "index.ts",
22
+ "LICENSE.md",
23
+ "README.md"
23
24
  ],
24
25
  "pi": {
25
26
  "extensions": [
@@ -19,8 +19,8 @@ const DEFAULT_INLINE_TEXT_OPTIONS: Required<InlineTextOptions> = {
19
19
  /**
20
20
  * Text component that renders inline and truncates it to fit the given width.
21
21
  *
22
- * The given width is a budget, not a guaranteed rendered width. After rendering, callers should
23
- * check the result with visibleWidth(), because the rendered width may be smaller than the budget.
22
+ * The given width is a budget, not a guaranteed rendered width. After rendering, check the result
23
+ * with visibleWidth(), because the rendered width may be smaller than the budget.
24
24
  */
25
25
  export class InlineText implements Component {
26
26
  private text: string;
@@ -12,7 +12,7 @@ const CONFIG_FILE = "spark.json";
12
12
 
13
13
  const cache = new Map<string, SparkConfig>();
14
14
 
15
- /** Load and validate spark.json once per session lifecycle; later calls return the cached result. */
15
+ /** Loads and validates spark.json once per session lifecycle; later calls return the cached result. */
16
16
  export function loadConfig(ctx: ExtensionContext): SparkConfig {
17
17
  const cached = cache.get(ctx.cwd);
18
18
  if (cached) return cached;
@@ -60,7 +60,7 @@ export class CreditsManager {
60
60
  // The active model may have changed while the request was in flight.
61
61
  if (ctx.model?.provider !== provider.id) return;
62
62
 
63
- ctx.ui.setStatus(STATUS_KEY, renderCredits(ctx.ui.theme, provider.label, credits));
63
+ ctx.ui.setStatus(STATUS_KEY, renderCredits(ctx.ui.theme, provider.label, credits, provider.link));
64
64
  } catch (error) {
65
65
  if (signal.aborted) return;
66
66
  if (ctx.model?.provider !== provider.id) return;
@@ -18,6 +18,7 @@ interface DeepSeekBalanceInfo {
18
18
  export const deepseekProvider: CreditsProvider = {
19
19
  id: PROVIDER,
20
20
  label: "DeepSeek",
21
+ link: "https://platform.deepseek.com/usage",
21
22
 
22
23
  async fetch(apiKey, signal): Promise<Credits> {
23
24
  const payload = await withAuth(http, apiKey).get(URL, { signal }).json<DeepSeekBalanceResponse>();
@@ -107,6 +107,7 @@ function moneyToNumber(money: Money | null | undefined): number | undefined {
107
107
  export const fireworksProvider: CreditsProvider = {
108
108
  id: PROVIDER,
109
109
  label: "Fireworks",
110
+ link: "https://app.fireworks.ai/account/billing",
110
111
 
111
112
  async fetch(apiKey, signal): Promise<Credits> {
112
113
  const name = await resolveAccount(apiKey, signal);
@@ -1,4 +1,4 @@
1
- import { toNumber } from "../../../utils/format";
1
+ import { convertToUSD, toNumber } from "../../../utils/format";
2
2
  import { http, withAuth } from "../../../utils/http";
3
3
 
4
4
  import type { Credits, CreditsLane, CreditsProvider } from "../types";
@@ -11,6 +11,7 @@ interface KimiCodeUsage {
11
11
  limit?: string | number;
12
12
  used?: string | number;
13
13
  remaining?: string | number;
14
+ resetTime?: string | null;
14
15
  }
15
16
 
16
17
  interface KimiCodeLimit {
@@ -24,6 +25,8 @@ interface KimiCodeBoosterWallet {
24
25
  amount?: string | number;
25
26
  amountLeft?: string | number;
26
27
  } | null;
28
+ monthlyChargeLimit?: { currency?: string } | null;
29
+ monthlyUsed?: { currency?: string } | null;
27
30
  }
28
31
 
29
32
  interface KimiCodeUsageResponse {
@@ -50,24 +53,24 @@ function formatWindowLabel(window?: { duration?: number; timeUnit?: string } | n
50
53
  if (!window?.duration) return "Limit";
51
54
 
52
55
  const duration = window.duration;
53
- const unit = window.timeUnit?.toUpperCase() ?? "";
56
+ const unit = window.timeUnit;
54
57
 
55
- if (unit === "TIME_UNIT_MINUTE") {
56
- if (duration >= 60 && duration % 60 === 0) return `${duration / 60}h`;
57
- return `${duration}m`;
58
- }
58
+ if (unit === "TIME_UNIT_MINUTE") return (duration >= 60 && duration % 60 === 0) ? `${duration / 60}h` : `${duration}m`;
59
59
  if (unit === "TIME_UNIT_HOUR") return `${duration}h`;
60
60
  if (unit === "TIME_UNIT_DAY") return `${duration}d`;
61
- if (unit === "TIME_UNIT_MONTH") return `${duration}mo`;
62
- return `${duration}${unit.replace("TIME_UNIT_", "").toLowerCase()}`;
61
+ if (unit === "TIME_UNIT_WEEK") return `${duration * 7}d`;
62
+ return "Limit";
63
63
  }
64
64
 
65
65
  function buildLane(label: string, detail: KimiCodeUsage): CreditsLane | undefined {
66
66
  const percent = toPercent(detail);
67
- return percent === undefined ? undefined : { label, percent };
67
+ if (percent === undefined) return undefined;
68
+
69
+ const resetAt = Date.parse(detail.resetTime ?? "");
70
+ return { label, percent, resetAt: Number.isFinite(resetAt) ? resetAt : undefined };
68
71
  }
69
72
 
70
- function formatSuffix(wallet?: KimiCodeBoosterWallet | null): string | undefined {
73
+ async function formatSuffix(wallet: KimiCodeBoosterWallet | null | undefined, signal: AbortSignal): Promise<string | undefined> {
71
74
  if (wallet?.balance?.type !== "BOOSTER") return undefined;
72
75
 
73
76
  const amount = toNumber(wallet.balance.amount);
@@ -75,7 +78,9 @@ function formatSuffix(wallet?: KimiCodeBoosterWallet | null): string | undefined
75
78
 
76
79
  const amountLeft = Math.max(0, toNumber(wallet.balance.amountLeft) ?? 0);
77
80
  const remaining = Math.round(amountLeft / BOOSTER_FIXED_POINT_CENTS) / 100;
78
- return `(Extra Usage $${remaining.toFixed(2)})`;
81
+ const currency = wallet.monthlyChargeLimit?.currency || wallet.monthlyUsed?.currency || "USD";
82
+ const remainingUSD = await convertToUSD(remaining, currency, signal);
83
+ return !!remainingUSD ? `(Extra Usage $${remainingUSD.toFixed(2)})` : undefined;
79
84
  }
80
85
 
81
86
  export const kimiCodeProvider: CreditsProvider = {
@@ -100,6 +105,6 @@ export const kimiCodeProvider: CreditsProvider = {
100
105
 
101
106
  if (lanes.length === 0) throw new Error("no usage data");
102
107
 
103
- return { type: "windows", lanes, suffix: formatSuffix(payload.boosterWallet) };
108
+ return { type: "windows", lanes, suffix: await formatSuffix(payload.boosterWallet, signal) };
104
109
  },
105
110
  };
@@ -30,6 +30,7 @@ interface CodexUsageResponse {
30
30
  interface CodexRateWindow {
31
31
  limit_window_seconds: number;
32
32
  used_percent?: number | string;
33
+ reset_at?: number;
33
34
  }
34
35
 
35
36
  export interface BankedRateLimitReset {
@@ -120,6 +121,7 @@ function toLane(window: CodexRateWindow): CreditsLane {
120
121
  return {
121
122
  label: prettyMilliseconds(window.limit_window_seconds * 1_000, { compact: true }),
122
123
  percent: parseUsedPercent(window),
124
+ resetAt: !!window.reset_at ? window.reset_at * 1_000 : undefined,
123
125
  };
124
126
  }
125
127
 
@@ -131,6 +133,7 @@ function parseUsedPercent(window?: CodexRateWindow | null): number | undefined {
131
133
  export const openaiCodexProvider: CreditsProvider = {
132
134
  id: PROVIDER,
133
135
  label: "Codex",
136
+ link: "https://chatgpt.com/#settings/Usage",
134
137
 
135
138
  async fetch(apiKey, signal): Promise<Credits> {
136
139
  const client = createClient(apiKey);
@@ -16,6 +16,7 @@ interface OpenRouterCreditsResponse {
16
16
  export const openrouterProvider: CreditsProvider = {
17
17
  id: PROVIDER,
18
18
  label: "OpenRouter",
19
+ link: "https://openrouter.ai/settings/credits",
19
20
 
20
21
  async fetch(apiKey, signal): Promise<Credits> {
21
22
  const payload = await withAuth(http, apiKey).get(URL, { signal }).json<OpenRouterCreditsResponse>();
@@ -1,3 +1,6 @@
1
+ import { hyperlink } from "@earendil-works/pi-tui";
2
+ import prettyMilliseconds from "pretty-ms";
3
+
1
4
  import type { Theme } from "@earendil-works/pi-coding-agent";
2
5
  import type { Credits, CreditsLane } from "./types";
3
6
 
@@ -6,12 +9,13 @@ const WINDOWS_ERROR = 90;
6
9
  const BALANCE_WARNING = 10;
7
10
  const BALANCE_ERROR = 5;
8
11
 
9
- export function renderCredits(theme: Theme, label: string, credits: Credits): string {
12
+ export function renderCredits(theme: Theme, label: string, credits: Credits, link?: string): string {
10
13
  const styledLabel = theme.fg("dim", label ? `${label} ` : "");
11
14
  const value = credits.type === "windows" ? renderWindows(theme, credits) : renderBalance(theme, credits);
12
15
  const suffix = credits.suffix ? ` ${theme.fg("dim", credits.suffix)}` : "";
13
16
 
14
- return `${styledLabel}${value}${suffix}`;
17
+ const text = `${styledLabel}${value}${suffix}`;
18
+ return link ? hyperlink(text, link) : text;
15
19
  }
16
20
 
17
21
  export function renderError(theme: Theme, label: string, message: string): string {
@@ -26,11 +30,11 @@ function renderWindows(theme: Theme, credits: Extract<Credits, { type: "windows"
26
30
  }
27
31
 
28
32
  function renderLane(theme: Theme, lane: CreditsLane): string {
29
- const text = `${lane.label} ${lane.percent === undefined ? "?" : lane.percent.toFixed(0)}%`;
33
+ const percent = `${lane.label} ${lane.percent === undefined ? "?" : lane.percent.toFixed(0)}%`;
34
+ const color = lane.percent && lane.percent > WINDOWS_ERROR ? "error" : lane.percent && lane.percent > WINDOWS_WARNING ? "warning" : "success";
35
+ const resetAt = !!lane.resetAt ? ` ${theme.fg("dim", `[⟳ ${prettyMilliseconds(Math.max(0, lane.resetAt - Date.now()), { compact: true })}]`)}` : "";
30
36
 
31
- if (lane.percent && lane.percent > WINDOWS_ERROR) return theme.fg("error", text);
32
- if (lane.percent && lane.percent > WINDOWS_WARNING) return theme.fg("warning", text);
33
- return theme.fg("success", text);
37
+ return `${theme.fg(color, percent)}${resetAt}`;
34
38
  }
35
39
 
36
40
  function renderBalance(theme: Theme, credits: Extract<Credits, { type: "balance" }>): string {
@@ -15,6 +15,8 @@ export type Credits = (
15
15
  export interface CreditsLane {
16
16
  label: string;
17
17
  percent: number | undefined;
18
+ /** Timestamp in milliseconds. */
19
+ resetAt?: number;
18
20
  }
19
21
 
20
22
  export type RefreshCredits = (ctx: ExtensionContext) => Promise<void>;
@@ -23,6 +25,7 @@ export type RefreshCredits = (ctx: ExtensionContext) => Promise<void>;
23
25
  export interface CreditsProvider {
24
26
  readonly id: CreditsProviderId;
25
27
  readonly label: string;
28
+ readonly link?: string;
26
29
  fetch(apiKey: string, signal: AbortSignal): Promise<Credits>;
27
30
  register?(pi: ExtensionAPI, ctx: ExtensionContext, refresh: RefreshCredits): void;
28
31
  }
@@ -53,12 +53,12 @@ class Editor extends CustomEditor {
53
53
  const lines = super.render(width);
54
54
  if (lines.length === 0) return lines;
55
55
 
56
- lines[0] = this.renderTopBorder(width);
56
+ lines[0] = this.getTopBorder(width);
57
57
 
58
58
  return lines;
59
59
  }
60
60
 
61
- private renderTopBorder(width: number): string {
61
+ private getTopBorder(width: number): string {
62
62
  const theme = this.ctx.ui.theme;
63
63
 
64
64
  const left = this.getLeft();
@@ -63,7 +63,7 @@ class FooterComponent implements Component {
63
63
  return [statusesText, styledCostText, styledContextUsageText].filter(Boolean).join(this.theme.fg("dim", " · "));
64
64
  }
65
65
 
66
- /** Get extension statuses, sorted by key alphabetically. */
66
+ /** Gets extension statuses, sorted alphabetically by key. */
67
67
  private getStatusesText(): string {
68
68
  const extensionStatuses = this.footerData.getExtensionStatuses();
69
69
  if (extensionStatuses.size === 0) return "";
@@ -3,7 +3,7 @@ import * as z from "zod";
3
3
 
4
4
  const MIN_IDLE_MS = 5_000;
5
5
 
6
- /** Accept a millisecond number or a human-readable duration (e.g., "3m"), normalized to milliseconds. */
6
+ /** Accepts a millisecond number or a human-readable duration (e.g., "3m"), normalized to milliseconds. */
7
7
  export const idleTimeoutSchema = z
8
8
  .union([z.number(), z.string()])
9
9
  .transform((value, ctx) => {
@@ -76,7 +76,7 @@ export class IdleListener<T> {
76
76
  this.enterCallbacks.forEach((callback) => callback(ctx));
77
77
  }
78
78
 
79
- /** Emit on every wake signal, even when the listener is already active. */
79
+ /** Emits on every wake signal, even when the listener is already active. */
80
80
  wake(ctx: T): void {
81
81
  this.stop();
82
82
  this.state = "active";
@@ -30,7 +30,7 @@ export class TitleManager {
30
30
  this.config = config;
31
31
  }
32
32
 
33
- /** Generate and set the session title once, silently, from the current context. */
33
+ /** Generates and sets the session title once, silently, from the current context. */
34
34
  async run(ctx: ExtensionContext): Promise<void> {
35
35
  if (this.pi.getSessionName() || this.inflight) return;
36
36
 
@@ -36,7 +36,7 @@ export function formatCwd(cwd: string, home: string): string {
36
36
  return shortenPath(displayCwd);
37
37
  }
38
38
 
39
- /** Shorten every path component except the first and last to one character, like fish `prompt_pwd`. */
39
+ /** Shortens every path component except the first and last to one character, like fish `prompt_pwd`. */
40
40
  function shortenPath(path: string): string {
41
41
  const parts = path.split(sep);
42
42
  const lastIndex = parts.length - 1;
@@ -47,7 +47,7 @@ function shortenPath(path: string): string {
47
47
  }).join(sep);
48
48
  }
49
49
 
50
- /** Replace newlines, tabs, carriage returns with space, then collapse multiple spaces */
50
+ /** Replaces newlines, tabs, and carriage returns with spaces, then collapses multiple spaces. */
51
51
  export function sanitizeText(text: string): string {
52
52
  return text
53
53
  .replace(/[\r\n\t]/g, " ")
@@ -55,7 +55,7 @@ export function sanitizeText(text: string): string {
55
55
  .trim();
56
56
  }
57
57
 
58
- /** Coerce a possibly-stringified numeric value to a finite number, or `undefined`. */
58
+ /** Coerces a possibly-stringified numeric value to a finite number, or `undefined`. */
59
59
  export function toNumber(value?: string | number | null): number | undefined {
60
60
  if (value === undefined || value === null) return undefined;
61
61
  const parsed = typeof value === "number" ? value : Number(value);
@@ -68,7 +68,7 @@ interface FrankfurterRateResponse {
68
68
  rate?: string | number;
69
69
  }
70
70
 
71
- /** Convert an amount in the given currency to USD via the Frankfurter API. */
71
+ /** Converts an amount in the given currency to USD via the Frankfurter API. */
72
72
  export async function convertToUSD(amount: number | undefined, currency: string | undefined, signal: AbortSignal): Promise<number | undefined> {
73
73
  if (amount === undefined) return undefined;
74
74
  if (!currency || currency === "USD") return amount;
@@ -27,7 +27,7 @@ type ThinkingLevelSelection = {
27
27
  };
28
28
 
29
29
  /**
30
- * Complete a one-shot background request, using an isolated session for OpenAI Codex models.
30
+ * Completes a one-shot background request, using an isolated session for OpenAI Codex models.
31
31
  * See [the investigation](../../docs/background-model-calls-and-openai-codex-sessions.md).
32
32
  */
33
33
  export const completeBackground: typeof completeSimple = async (model, context, options) => {
@@ -43,7 +43,7 @@ export const completeBackground: typeof completeSimple = async (model, context,
43
43
  };
44
44
 
45
45
  /**
46
- * Resolve the model and thinking level for a background feature (recap, title, ...).
46
+ * Resolves the model and thinking level for a background feature (recap, title, ...).
47
47
  *
48
48
  * `feature` names the config section so warnings can point at the offending fields. When the
49
49
  * feature's model config is incomplete or unavailable, this falls back to the session's main
@@ -26,9 +26,9 @@ export function isUsage(value: unknown): value is Usage {
26
26
  }
27
27
 
28
28
  /**
29
- * Extract usage from a session entry.
29
+ * Extracts usage from a session entry.
30
30
  *
31
- * `usage` live in different fields depending on the entry type:
31
+ * `usage` lives in different fields depending on the entry type:
32
32
  *
33
33
  * - `message` carries them on `message`.
34
34
  * - `custom` on `data`.