@gavin-hu/my-pi-agent 0.16.0 → 0.18.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 (200) hide show
  1. package/README.md +29 -15
  2. package/README.zh-CN.md +27 -15
  3. package/extensions/bytefly/README.md +195 -115
  4. package/extensions/bytefly/footer/collect/entries.ts +1 -6
  5. package/extensions/bytefly/footer/collect/snapshot.ts +23 -9
  6. package/extensions/bytefly/footer/price/price.ts +12 -8
  7. package/extensions/bytefly/footer/register.ts +13 -1
  8. package/extensions/bytefly/footer/types.ts +11 -0
  9. package/extensions/bytefly/footer/unpriced.ts +36 -0
  10. package/extensions/bytefly/header/component.ts +15 -29
  11. package/extensions/bytefly/header/identity.ts +71 -0
  12. package/extensions/bytefly/header/register.ts +9 -3
  13. package/extensions/bytefly/index.ts +13 -5
  14. package/extensions/bytefly/message/format.ts +20 -13
  15. package/extensions/bytefly/message/register.ts +8 -7
  16. package/extensions/bytefly/notify/types.ts +1 -1
  17. package/extensions/bytefly/panel/commands.ts +46 -25
  18. package/extensions/bytefly/panel/format.ts +49 -14
  19. package/extensions/bytefly/panel/join.ts +35 -9
  20. package/extensions/bytefly/panel/settings.ts +29 -39
  21. package/extensions/bytefly/panel/skills.ts +51 -0
  22. package/extensions/bytefly/panel/tui/extensions-view.ts +7 -61
  23. package/extensions/bytefly/panel/tui/frame.ts +9 -1
  24. package/extensions/bytefly/panel/tui/list-view.ts +72 -0
  25. package/extensions/bytefly/panel/tui/nav.ts +71 -3
  26. package/extensions/bytefly/panel/tui/settings-section.ts +250 -0
  27. package/extensions/bytefly/panel/tui/skills-view.ts +50 -0
  28. package/extensions/bytefly/panel/tui.ts +223 -331
  29. package/extensions/bytefly/panel/types.ts +26 -8
  30. package/extensions/bytefly/picker/discovery.ts +32 -27
  31. package/extensions/bytefly/picker/resources.ts +16 -8
  32. package/extensions/bytefly/picker/runtime.ts +62 -34
  33. package/extensions/bytefly/picker/toggle.ts +16 -10
  34. package/extensions/bytefly/picker/types.ts +31 -13
  35. package/extensions/bytefly/update/format.ts +66 -8
  36. package/extensions/bytefly/update/patch.ts +66 -0
  37. package/extensions/bytefly/update/register.ts +4 -11
  38. package/extensions/bytefly/update/release.ts +65 -0
  39. package/extensions/bytefly/update/state.ts +14 -0
  40. package/extensions/bytefly/update/suppress.ts +47 -29
  41. package/extensions/bytefly/update/types.ts +15 -5
  42. package/extensions/check/tui.ts +2 -0
  43. package/extensions/context/README.md +21 -11
  44. package/extensions/context/format.ts +10 -8
  45. package/extensions/context/report.ts +21 -8
  46. package/extensions/context/tui.ts +26 -10
  47. package/extensions/context/types.ts +5 -3
  48. package/extensions/file-browse/README.md +89 -22
  49. package/extensions/file-browse/chrome.ts +83 -0
  50. package/extensions/file-browse/client.ts +74 -459
  51. package/extensions/file-browse/config.ts +12 -3
  52. package/extensions/file-browse/diff-html.ts +94 -0
  53. package/extensions/file-browse/html.ts +26 -152
  54. package/extensions/file-browse/live-client.ts +47 -1
  55. package/extensions/file-browse/live.ts +35 -14
  56. package/extensions/file-browse/palette.ts +224 -0
  57. package/extensions/file-browse/rev.ts +42 -0
  58. package/extensions/file-browse/router.ts +27 -6
  59. package/extensions/file-browse/server.ts +7 -0
  60. package/extensions/file-browse/styles.ts +10 -3
  61. package/extensions/file-browse/tree.ts +381 -0
  62. package/extensions/file-read/README.md +4 -1
  63. package/extensions/file-read/extract/odt.ts +7 -5
  64. package/extensions/goal/plan-route.ts +8 -2
  65. package/extensions/goal/tools.ts +6 -11
  66. package/extensions/job/README.md +7 -5
  67. package/extensions/job/index.ts +35 -52
  68. package/extensions/job/tools.ts +51 -77
  69. package/extensions/memory/README.md +3 -3
  70. package/extensions/memory/tools.ts +4 -6
  71. package/extensions/memory/tui.ts +5 -1
  72. package/extensions/plan/README.md +333 -84
  73. package/extensions/plan/commands.ts +73 -7
  74. package/extensions/plan/feedback.ts +300 -63
  75. package/extensions/plan/index.ts +1 -1
  76. package/extensions/plan/plan-index.ts +4 -2
  77. package/extensions/plan/plan-text.ts +18 -1
  78. package/extensions/plan/plans.ts +184 -58
  79. package/extensions/plan/review-prompt.ts +93 -0
  80. package/extensions/plan/review.ts +95 -95
  81. package/extensions/plan/runtime.ts +4 -2
  82. package/extensions/plan/split.ts +87 -0
  83. package/extensions/plan/steps.ts +123 -107
  84. package/extensions/plan/tools/cancel.ts +79 -0
  85. package/extensions/plan/tools/enter.ts +17 -12
  86. package/extensions/plan/tools/exit.ts +148 -59
  87. package/extensions/plan/tools/steps.ts +7 -19
  88. package/extensions/plan/tools/write.ts +29 -31
  89. package/extensions/plan/tools.ts +6 -3
  90. package/extensions/plan/tui.ts +60 -15
  91. package/extensions/plan/types.ts +45 -3
  92. package/extensions/plan/web-chrome.ts +102 -0
  93. package/extensions/plan/web-client.ts +177 -446
  94. package/extensions/plan/web-collab.ts +207 -0
  95. package/extensions/plan/web-comments.ts +269 -0
  96. package/extensions/plan/web-markdown.ts +222 -0
  97. package/extensions/plan/web-page.ts +131 -19
  98. package/extensions/plan/web-router.ts +148 -32
  99. package/extensions/plan/web-share-session.ts +197 -0
  100. package/extensions/plan/web-share.ts +169 -0
  101. package/extensions/plan/web-streams.ts +124 -0
  102. package/extensions/plan/web-tokens.ts +63 -0
  103. package/extensions/plan/web.ts +193 -45
  104. package/extensions/question/README.md +3 -0
  105. package/extensions/question/dialogs.ts +91 -1
  106. package/extensions/question/tools.ts +2 -1
  107. package/extensions/rewind/checklist.ts +4 -0
  108. package/extensions/rewind/review-tui.ts +3 -1
  109. package/extensions/rewind/rewind-tui.ts +4 -0
  110. package/extensions/session-bus/README.md +247 -0
  111. package/extensions/session-bus/commands.ts +165 -0
  112. package/extensions/session-bus/format.ts +124 -0
  113. package/extensions/session-bus/index.ts +69 -0
  114. package/extensions/session-bus/notice.ts +58 -0
  115. package/extensions/session-bus/protocol.ts +134 -0
  116. package/extensions/session-bus/result.ts +243 -0
  117. package/extensions/session-bus/rows.ts +169 -0
  118. package/extensions/session-bus/runtime.ts +575 -0
  119. package/extensions/session-bus/store.ts +329 -0
  120. package/extensions/session-bus/team.ts +102 -0
  121. package/extensions/session-bus/tools.ts +227 -0
  122. package/extensions/session-bus/tui.ts +394 -0
  123. package/extensions/session-bus/types.ts +98 -0
  124. package/extensions/subagent/README.md +26 -13
  125. package/extensions/subagent/format.ts +72 -25
  126. package/extensions/subagent/index.ts +21 -47
  127. package/extensions/subagent/orchestrate.ts +18 -41
  128. package/extensions/subagent/render.ts +29 -42
  129. package/extensions/subagent/stream.ts +24 -18
  130. package/extensions/subagent/types.ts +7 -0
  131. package/extensions/todo/tools.ts +5 -6
  132. package/extensions/todo/tui.ts +5 -1
  133. package/extensions/watch/README.md +9 -5
  134. package/extensions/watch/index.ts +25 -44
  135. package/extensions/watch/tools.ts +31 -59
  136. package/extensions/wechat/README.md +45 -36
  137. package/extensions/wechat/bridge.ts +46 -48
  138. package/extensions/wechat/client.ts +1 -4
  139. package/extensions/wechat/commands.ts +3 -3
  140. package/extensions/wechat/deliver.ts +57 -37
  141. package/extensions/wechat/interaction.ts +54 -18
  142. package/extensions/wechat/login-screen.ts +2 -3
  143. package/extensions/wechat/notices.ts +9 -7
  144. package/extensions/wechat/peer-worker.ts +19 -34
  145. package/extensions/wechat/presence.ts +3 -4
  146. package/extensions/wechat/prompt.ts +53 -23
  147. package/extensions/wechat/reply-pipeline.ts +12 -4
  148. package/extensions/wechat/slash.ts +14 -0
  149. package/extensions/wechat/status-screen.ts +2 -2
  150. package/extensions/wechat/tools.ts +3 -11
  151. package/extensions/worktree/README.md +48 -12
  152. package/extensions/worktree/commands.ts +109 -65
  153. package/extensions/worktree/enter.ts +1 -1
  154. package/extensions/worktree/exit.ts +11 -1
  155. package/extensions/worktree/git.ts +5 -0
  156. package/extensions/worktree/lifecycle.ts +9 -1
  157. package/extensions/worktree/registry.ts +11 -5
  158. package/extensions/worktree/screen.ts +263 -0
  159. package/extensions/worktree/status.ts +84 -40
  160. package/lib/README.md +12 -7
  161. package/lib/claims/overlap.ts +43 -0
  162. package/lib/config.ts +12 -0
  163. package/lib/format.ts +6 -2
  164. package/lib/http/router.ts +40 -13
  165. package/lib/http/server.ts +27 -13
  166. package/lib/interaction.ts +28 -1
  167. package/lib/notice.ts +29 -2
  168. package/lib/plan-entry.ts +7 -2
  169. package/lib/plans/sections.ts +172 -0
  170. package/lib/plans/setting.ts +52 -0
  171. package/lib/plans/split.ts +215 -0
  172. package/lib/plans/store.ts +19 -0
  173. package/lib/plans/team.ts +151 -0
  174. package/lib/qr.ts +64 -0
  175. package/lib/repo-key.ts +74 -0
  176. package/lib/report.ts +117 -25
  177. package/lib/requirements.ts +1 -2
  178. package/lib/tool-result.ts +54 -4
  179. package/lib/tui/README.md +30 -8
  180. package/lib/tui/chrome.ts +27 -6
  181. package/lib/tui/dock-screen.ts +91 -19
  182. package/lib/tui/gauge.ts +9 -5
  183. package/lib/tui/line-pane.ts +15 -4
  184. package/lib/tui/tool.ts +23 -4
  185. package/lib/usage.ts +26 -0
  186. package/lib/web/README.md +131 -0
  187. package/lib/web/base.ts +19 -2
  188. package/lib/web/components.ts +10 -6
  189. package/lib/web/layout.ts +2 -0
  190. package/lib/web/markup.ts +2 -1
  191. package/lib/web/runtime.ts +103 -25
  192. package/lib/web/tokens.ts +23 -7
  193. package/package.json +5 -2
  194. package/skills/changelog/SKILL.md +57 -45
  195. package/skills/init/SKILL.md +80 -45
  196. package/skills/init/references/agents-md-quality.md +26 -2
  197. package/skills/init/references/interview-questions.md +36 -14
  198. package/skills/next/SKILL.md +209 -0
  199. package/skills/parallel-dev/SKILL.md +150 -0
  200. package/extensions/wechat/qrcode.ts +0 -46
@@ -4,13 +4,14 @@
4
4
  this package adds: one themed startup header whose two-tone nameplate carries
5
5
  the agent and chrome identities, one compact, colorful, width-adaptive two-line
6
6
  footer, a two-row `You` nameplate that opens each user message, a receipt rule that
7
- records each completed turn in the transcript, one keyboard-driven screen with two
8
- sections — Extensions, every resolved Pi extension with its enable checkbox and
9
- its health, and Settings, the common app and `bytefly.json` preferences — and
10
- an opt-in notify capability that raises an OS notification when a run finishes,
7
+ records each completed turn in the transcript, one keyboard-driven screen with
8
+ three sections — Extensions, every resolved Pi extension with its enable
9
+ checkbox and its health; Skills, every resolved Pi skill with the same checkbox
10
+ and its declared description; and Settings, the common app and `bytefly.json`
11
+ preferences — and an opt-in notify capability that raises an OS notification when a run finishes,
11
12
  a job finishes, or the agent asks for input, and a package-update check that
12
- replaces Pi's startup block with one notice and marks bytefly's own new version
13
- on the header.
13
+ replaces Pi's startup blocks — the package list and Pi's own release — with one
14
+ notice each and marks a new version on the header.
14
15
  DeepSeek is priced from the provider's published yuan rates and peak tariff by
15
16
  default; set `price.currency.code` to `USD` to price it from the provider's
16
17
  published dollar table instead, under the same peak windows, with Pi's recorded
@@ -35,7 +36,7 @@ How the `run_doctor` call and its result look in the transcript — the call lin
35
36
  The extension owns ten surfaces: the startup header, the footer, the
36
37
  user-message marker, the rule between completed turns, the notice block for
37
38
  shared transcript notices, the tool-block frame, the live working line, the
38
- two-section control center, notifications, and the package-update check.
39
+ three-section control center, notifications, and the update check.
39
40
 
40
41
  **Header.** A nameplate: a two-tone half-block mark from the active theme's
41
42
  `accent` / `warn` roles, the agent identity (`Pi`, bold, and its version), the
@@ -58,9 +59,9 @@ that cannot render half blocks the mark falls back to a two-tone `Pi` wordmark.
58
59
  / commands · ! bash · !! bash (no context) · /bytefly extensions
59
60
  ```
60
61
 
61
- As the terminal narrows, the identity sheds the update marker, then the chrome
62
- version, then the chrome line, then the agent name, and the help rows drop whole
63
- keys, so nothing wraps or clips mid-word. Height sheds the same way: at 28 rows
62
+ As the terminal narrows, the identity sheds the chrome marker, then the chrome
63
+ version, then the chrome line, then Pi's marker with the agent name, and the help
64
+ rows drop whole keys, so nothing wraps or clips mid-word. Height sheds the same way: at 28 rows
64
65
  all three help groups print, below 28 the middle group (the expand and model
65
66
  chords) goes first, below 22 only the `/` commands row survives, and below 16 the
66
67
  help block and the leading blank row go, leaving the nameplate and its rule. An
@@ -152,6 +153,15 @@ default, turns it off. The check reads the total the footer already priced, and
152
153
  the footer exists only in `tui` sessions, so a print or JSON run has no budget
153
154
  alert; the footer's own numbers are visible in every interactive session.
154
155
 
156
+ **Unpriced records.** `CNY` has no fallback, so a record for a model with no
157
+ `price.rates` entry contributes nothing to the total — with nothing on screen
158
+ saying so. The footer counts those records on the pass it already prices, and
159
+ one `bytefly · Records with no CNY rate` notice names the count and the two
160
+ fixes: switch `price.currency.code` to `USD` (Pi's catalog is per model, tiers
161
+ included) or add yuan `price.rates` entries. It fires once per session, on the
162
+ run that settles, like the budget alert. `USD` never counts one: Pi's recorded
163
+ amount covers every model.
164
+
155
165
  **User message.** Every user message opens with a two-row `You` nameplate —
156
166
  the label over a rule that spans the width — above the message:
157
167
 
@@ -317,7 +327,7 @@ See [The control center](#the-control-center).
317
327
  **Notify.** Off by default, one `notify` section in `bytefly.json` turns on OS
318
328
  notifications for unattended runs: when a full agent run settles, when a
319
329
  background job finishes, when the agent opens a prompt asking for input, and when
320
- a `watch` wake match fires while the agent is idle. The
330
+ an armed `watch` wake match fires as the agent becomes idle. The
321
331
  method follows the terminal (OSC 777, OSC 99, a Windows toast) or falls back to
322
332
  the platform notifier (`osascript`, `notify-send`); see
323
333
  [Notifications](#notifications).
@@ -329,10 +339,13 @@ with the time it was read, and posts one transcript notice listing every package
329
339
  plus `pi update --extensions`. This package's new version alone puts `↑0.12.0`
330
340
  after the header's chrome version and adds its release URL to the notice. A
331
341
  session inside the 24-hour window reuses the cache without a package-manager
332
- call, and `/bytefly update` re-runs the check on demand. `PI_OFFLINE` uses the
333
- cached marker with no notice, only `tui` starts the background check, and a
334
- failed read is silent and not cached, so the next session tries again; see
335
- [Update check](#update-check).
342
+ call, and `/bytefly update` re-runs the check on demand. Pi's own newer release
343
+ is drawn the same way: Pi resolves it from `pi.dev` and would draw `Update
344
+ Available`, and bytefly patches the method that draws it, so the release becomes
345
+ a notice naming `pi update` and the changelog and marks `Pi v1.3.0 ↑1.4.0` on
346
+ the agent line. `PI_OFFLINE` uses the cached marker with no notice, only `tui`
347
+ starts the background check, and a failed read is silent and not cached, so the
348
+ next session tries again; see [Update check](#update-check).
336
349
 
337
350
  ## Commands
338
351
 
@@ -340,11 +353,12 @@ failed read is silent and not cached, so the next session tries again; see
340
353
  |---|---|
341
354
  | `/bytefly [extension] [refresh]` | Open the control center on Extensions. In `tui` it mounts a docked list; every other mode prints the grouped listing, or one extension's full findings when named. |
342
355
  | `/bytefly settings` | Open the control center on Settings. Outside `tui` it prints one `Label: Value` line per setting. |
356
+ | `/bytefly skills` | Open the control center on Skills. Outside `tui` it prints the grouped skills listing with one row per skill. |
343
357
  | `/bytefly doctor [extension] [refresh]` | Print the doctor report. Outside `tui` it prints `run_doctor`'s text for every extension, or one named extension's findings; in `tui` it mounts the same docked screen. |
344
358
  | `/bytefly update` | Re-run the package update check now, ignoring the cache window, and report what it found — the updateable packages, this package's version and release URL when known, `PI_OFFLINE`, or an unreadable list. It resolves no packages and probes no extension. |
345
359
 
346
360
  Tab completes the subcommands, extension names after `doctor`, and `refresh`;
347
- `/bytefly settings` and `/bytefly update` take no name.
361
+ `/bytefly settings`, `/bytefly skills`, and `/bytefly update` take no name.
348
362
 
349
363
  ## Behaviour by mode
350
364
 
@@ -496,8 +510,9 @@ it with its own rates for the models they match:
496
510
  changes how the total is printed; the symbol follows the code.
497
511
  - **Which source.** Both currencies price a matched record from `rates`; only
498
512
  the unmatched case differs. `CNY` contributes nothing for a model it cannot
499
- price, while `USD` adds Pi's recorded dollar amount for that record, because
500
- that number is already dollars.
513
+ price and counts the record instead, so the session can name what its total
514
+ leaves out; `USD` adds Pi's recorded dollar amount for that record, because
515
+ that number is already dollars and already per model.
501
516
 
502
517
  For example, DeepSeek flash at `¥2` in and `¥8` out per million, with the
503
518
  published peak windows and `offPeakMultiplier: 0.5`, prices a 1M-in + 1M-out
@@ -578,25 +593,27 @@ and outcome as the width allows.
578
593
 
579
594
  ## The control center
580
595
 
581
- <img src="../../assets/bytefly.png" alt="The /bytefly control center: the Extensions and Settings section bar with the `Global · 10 extensions · 2 off · 1 missing` counts, one checkbox row per extension with its verdict, the focused extension's report, and the key hints" width="100%">
596
+ <img src="../../assets/bytefly.png" alt="The /bytefly control center: the Extensions, Skills, and Settings section bar with the `Global · 10 extensions · 2 off · 1 missing` counts, one checkbox row per extension with its verdict, the focused extension's report, and the key hints" width="100%">
582
597
 
583
598
  `/bytefly [extension] [refresh]` opens the control center on **Extensions**: a
584
599
  keyboard-driven dock list of every extension Pi resolves for the session, so the
585
- list matches what actually loads. `←`/`→` switch to **Settings**, where the same
586
- frame lists the curated preferences. `/bytefly settings` opens directly on that
587
- section. It merges the former extensions picker and doctor report into one row
588
- per extension: the picker's enable checkbox and label, then one verdict — `off`
589
- when the row is switched off in settings, `env disabled` when
590
- `PI_DISABLED_EXTENSIONS` excludes it, otherwise the doctor's worst-severity
591
- glyph and summary. The screen is drawn from the design system: a label-first
592
- `bytefly ────` title rule,
593
- the `Extensions · Settings` section bar beside the section's counts, one row
594
- grammar (`❯ ◼ name … summary`), and the shared `◼` / `◻` checkbox.
600
+ list matches what actually loads. `←`/`→` move to **Skills** and then
601
+ **Settings**, one section per press and stopping at the ends, where the same
602
+ frame lists every resolved skill and the curated preferences. `/bytefly skills`
603
+ and `/bytefly settings` open their section directly. It merges the former
604
+ extensions picker and doctor report into one row per extension: the picker's
605
+ enable checkbox and label, then one verdict — `off` when the row is switched off
606
+ in settings, `env disabled` when `PI_DISABLED_EXTENSIONS` excludes it, otherwise
607
+ the doctor's worst-severity glyph and summary. The screen is drawn from the
608
+ design system: a label-first `Bytefly ────` title rule,
609
+ the `Extensions · Skills · Settings` section bar beside the section's counts, one
610
+ row grammar (`❯ ◼ name … summary`), the shared `◼` / `◻` checkbox, and the closing
611
+ rule under the key hints that Pi's own list screens draw.
595
612
  `/bytefly doctor [extension] [refresh]` selects the doctor report, the same text
596
613
  the `run_doctor` tool returns; in `tui` it opens the same screen. `[extension]`
597
614
  narrows the Extensions section to one extension and `refresh` forces the first
598
615
  probe. Tab completes the subcommands, extension names after `doctor`, and
599
- `refresh`; `/bytefly settings` takes no name.
616
+ `refresh`; `/bytefly settings` and `/bytefly skills` take no name.
600
617
 
601
618
  The screen opens on the findings the session already has, and the Extensions
602
619
  section probes once on its first view (the hint shows `refreshing…` while it
@@ -644,15 +661,34 @@ installs or fetches a package.
644
661
  - Offers a reload after pending changes, so the new selection takes effect
645
662
  without leaving the session.
646
663
 
647
- **Settings.** The second section uses the same frame and the same `Tab` scope
648
- switch, with its own cursor. It is the shortlist a session changes: fourteen
664
+ **Skills.** The second section is the same list over Pi's skills: one row per
665
+ skill, grouped by source and sorted by name, labelled with the name its
666
+ `SKILL.md` declares (or the folder name when it declares none). `Space` writes
667
+ `+pattern` / `-pattern` into `skills` — or a package's `skills` filter — in the
668
+ active scope, and `Tab` and `x` behave as they do for extensions. A row's verdict
669
+ comes from the skill's own file: `off` when it is disabled, `hidden` when
670
+ frontmatter sets `disable-model-invocation` so only `/skill:<name>` loads it, and
671
+ `not loaded` with Pi's reason when the file was refused. The detail pane carries
672
+ the resolved path and the declared description, one line until `Enter` expands
673
+ it. There is nothing to probe, so `r` is not offered here; the metadata is read
674
+ once when the section first appears, so an edited `SKILL.md` shows on the next
675
+ open.
676
+
677
+ Themes and prompts have no section of their own, by decision rather than by
678
+ omission: a theme is one active selection — a scalar, global setting — and a
679
+ prompt template is a file Pi discovers from a directory, so neither is a scoped
680
+ enable list this screen's checkbox rows can write. Themes stay with `pi config`;
681
+ `ROADMAP.md` carries the reason under *Deliberately left thin*.
682
+
683
+ **Settings.** The third section uses the same frame and the same `Tab` scope
684
+ switch, with its own cursor. It is the shortlist a session changes: thirteen
649
685
  preferences on one flat line each, the value beside its label, and no group
650
686
  headings. The whole list fits a 24-row terminal, and the frame stops growing
651
687
  there however tall the terminal is.
652
688
 
653
689
  ```
654
- bytefly ──────────────────────────────────────────────────────────────
655
- Extensions · Settings Global · 14 settings
690
+ Bytefly ──────────────────────────────────────────────────────────────
691
+ Extensions · Skills · Settings Global · 13 settings
656
692
 
657
693
  ❯ ◻ Bytefly startup TUI Off
658
694
  ◼ Theme system
@@ -661,9 +697,7 @@ bytefly ────────────────────────
661
697
  ◼ Needs input On
662
698
  ◼ Job finished On
663
699
  ◼ Watcher matched On
664
- Delivery method Auto
665
700
  ◻ Wake when a job finishes Off
666
- ◻ Wake on a match Off
667
701
  ◼ Automatic snapshots On
668
702
  ◼ Proactive health check On
669
703
  Currency CNY (¥)
@@ -674,9 +708,10 @@ bytefly ────────────────────────
674
708
  Default · ~/.pi/agent/settings.json
675
709
 
676
710
  Esc close · ←/→ · Space change · Tab scope · u reset · J JSON · ↑/↓ select
711
+ ──────────────────────────────────────────────────────────────────────
677
712
  ```
678
713
 
679
- <img src="../../assets/bytefly-settings.png" alt="The /bytefly Settings section: one flat list of fourteen preferences with each value beside its label, the `Global · 14 settings` counts, and a three-row detail pane naming the focused row's source, description, and file" width="100%">
714
+ <img src="../../assets/bytefly-settings.png" alt="The /bytefly Settings section: one flat list of thirteen preferences with each value beside its label, the `Global · 13 settings` counts, and a three-row detail pane naming the focused row's source, description, and file" width="100%">
680
715
 
681
716
  | Row | Source | Values |
682
717
  |---|---|---|
@@ -687,9 +722,7 @@ bytefly ────────────────────────
687
722
  | Needs input | `notify.needsInput` | Off, On |
688
723
  | Job finished | `notify.jobFinished` | Off, On |
689
724
  | Watcher matched | `notify.matchFound` | Off, On |
690
- | Delivery method | `notify.method` | Auto, OSC 777, OSC 99, Windows toast, macOS, Linux |
691
725
  | Wake when a job finishes | `job.wakeOnFinish` | Off, On |
692
- | Wake on a match | `watch.wakeOnMatch` | Off, On |
693
726
  | Automatic snapshots | `rewind.autoSnapshots` | Off, On |
694
727
  | Proactive health check | `doctor.proactive` | Off, On |
695
728
  | Currency | `price.currency.code` | CNY, USD |
@@ -720,22 +753,22 @@ shows where the value comes from — `Global · ~/.pi/agent/bytefly.json`, `Proj
720
753
  `Default · <the active scope's file>`; an app row names the personal
721
754
  `settings.json`. A successful change marks the screen `Saved · reload to apply`
722
755
  — even when the terminal is too short for the detail body — and closing offers
723
- the same reload confirm as an extension toggle.
756
+ the same reload confirm as an extension or skill toggle.
724
757
 
725
- The list is capped at fourteen rows so the screen keeps fitting a 24-row
758
+ The list is capped at thirteen rows so the screen keeps fitting a 24-row
726
759
  terminal: adding a setting means removing one (`panel/panel.test.ts` holds the
727
760
  ceiling). Everything else stays in `bytefly.json` — the tuning numbers, the
728
761
  cosmetic labels, and the Pi preferences Pi's own `/settings` owns — and
729
762
  `test/settings-coverage.test.ts` keeps the split honest: every loader key is
730
- either a row or a declared JSON-only edit with the reason it left. Four
731
- `bytefly.json` sections therefore have no row at all (`chrome`, `goal`,
732
- `worktree`, `memory`), as do `notify.title`, `doctor.timeoutMs`,
733
- `price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`, and
734
- `job.detachedByDefault` inside sections that do. Each is documented in
735
- [`docs/configuration.md`](../../docs/configuration.md).
736
-
737
- Three of the six sections belong to other extensions (`rewind`, `job`, and
738
- `watch`). The screen cannot import their normalizers, so it reports the leaf as
763
+ either a row or a declared JSON-only edit with the reason it left. Six
764
+ `bytefly.json` sections therefore have no row at all (`chrome`, `goal`, `plan`,
765
+ `watch`, `worktree`, `memory`), as do `notify.title`, `doctor.timeoutMs`,
766
+ `price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`,
767
+ `job.detachedByDefault`, and `watch.wakeOnMatch` inside sections that do. Each is
768
+ documented in [`docs/configuration.md`](../../docs/configuration.md).
769
+
770
+ Two of the five sections belong to other extensions (`rewind` and `job`). The
771
+ screen cannot import their normalizers, so it reports the leaf as
739
772
  the file states it and declares the loader's default; the same test holds the
740
773
  catalogue to every loader's defaults and bounds in both directions.
741
774
 
@@ -747,7 +780,7 @@ with `true` or `false`.
747
780
 
748
781
  App rows are **Global only**: Pi's setters for them write the personal
749
782
  `settings.json`, and only resource paths have public project setters. Project
750
- scope therefore lists the twelve `bytefly.json` rows and a
783
+ scope therefore lists the eleven `bytefly.json` rows and a
751
784
  `App settings are Global only.` note rather than promising a write that cannot
752
785
  happen. A `bytefly.json` row writes one leaf in the selected scope (a depth-1
753
786
  key, or a nested one such as `price.currency.code`) through a per-key writer, so
@@ -759,16 +792,19 @@ The non-`tui` form prints the headline and one `Label: Value` row per line, in
759
792
  screen order:
760
793
 
761
794
  ```
762
- bytefly: Settings · Global · 14 settings
795
+ bytefly: Settings · Global · 13 settings
763
796
  Bytefly startup TUI: Off
764
- Theme: system
765
- Desktop notifications: Off
797
+ Theme: bytefly-dark
798
+ Desktop notifications: On
766
799
  Turn finished: On
767
800
  Needs input: On
768
801
  Job finished: On
769
802
  Watcher matched: On
770
- Delivery method: Auto
771
- ...
803
+ Wake when a job finishes: On
804
+ Automatic snapshots: On
805
+ Proactive health check: On
806
+ Currency: CNY (¥)
807
+ Session budget: 5
772
808
  ```
773
809
 
774
810
  The doctor side probes every declared extension and reports each check as `ok`,
@@ -803,21 +839,21 @@ headline; a named extension prints its full findings instead.
803
839
 
804
840
  | Key | Effect |
805
841
  |---|---|
806
- | `←` / `→` | Show the Extensions or Settings section. |
807
- | `Space` | Toggle the focused extension (Extensions); change the focused setting (Settings), or open the editor on a text row. |
808
- | `x` | Clear the focused extension's project override (Extensions, Project scope). |
809
- | `Enter` | Expand or collapse the focused extension's findings (Extensions); change the focused setting, or open the editor on a text row (Settings). |
842
+ | `←` / `→` | Show the previous or next section — Extensions, Skills, Settings; the ends stop. |
843
+ | `Space` | Toggle the focused extension or skill; change the focused setting, or open the editor on a text row. |
844
+ | `x` | Clear the focused resource's project override (Extensions and Skills, Project scope). |
845
+ | `Enter` | Expand or collapse the focused extension's findings, or the focused skill's description; change the focused setting, or open the editor on a text row (Settings). |
810
846
  | `u` | Delete the focused setting's key so its default applies again (Settings, `bytefly.json` rows). |
811
847
  | `J` | Show or hide the focused row's whole section as stored (Settings, `bytefly.json` rows). |
812
- | `[` / `]` | Jump to the previous or next group (Settings). |
848
+ | `[` / `]` | Jump to the previous or next group (Extensions and Skills). |
813
849
  | `←` / `→`, `Home` / `End` (`Ctrl+A` / `Ctrl+E`) | Move the editor's caret while a text row is being edited. |
814
850
  | `Backspace` / `Delete`, `Ctrl+U` | Edit the buffer: delete a character, or clear it. |
815
851
  | `Enter` / `Esc` (editing) | Save the buffer, or cancel and restore the stored value. |
816
- | `Tab` | Switch between Global and Project scope, in either section. |
852
+ | `Tab` | Switch between Global and Project scope, in any section. |
817
853
  | `r` | Re-probe the doctor (Extensions). |
818
- | `↑`/`↓`, `j`/`k` | Move the selection, in either section. |
819
- | `PgUp`/`PgDn` | Move a page, in either section. |
820
- | `g` / `G`, `Home` / `End` | Jump to the first or last row, in either section. |
854
+ | `↑`/`↓`, `j`/`k` | Move the selection, in any section. |
855
+ | `PgUp`/`PgDn` | Move a page, in any section. |
856
+ | `g` / `G`, `Home` / `End` | Jump to the first or last row, in any section. |
821
857
  | `Esc` / `Ctrl+C` | Close the screen. |
822
858
 
823
859
  Mouse wheel scrolling and clicking a row to focus it work; every action also
@@ -831,7 +867,7 @@ has a keyboard path.
831
867
  | rewind | `git` | — |
832
868
  | document | — | — |
833
869
  | subagent | a runnable nested `pi` | project-local agents need a trusted project |
834
- | plan | — | `git` for project-local `.pi/plans`; an interactive UI |
870
+ | plan | — | an interactive UI |
835
871
  | memory | — | `git` for the project-scope root |
836
872
  | file-browse | — | `git` for the branch chip; the browser opener is best-effort |
837
873
  | web-access | — | `unpdf` |
@@ -863,12 +899,12 @@ of `bytefly.json` (see [Configuration](#configuration)):
863
899
  - **A background job finished.** The [job](../job/) extension announces each
864
900
  terminal transition on the shared `pi.events` bus
865
901
  (`my-pi-agent/job-finished`); bytefly listens and never imports it.
866
- - **A watcher matched.** A [watch](../watch/) whose `wake` is on matched while the
867
- agent was idle, and announced it on `my-pi-agent/watch-match` with the cycle's
902
+ - **A watcher matched.** A [watch](../watch/) whose `wake` is on matched, and
903
+ announced it on `my-pi-agent/watch-match` with the cycle's
868
904
  count, the watcher, and its newest line. The body names that line, sanitized and
869
905
  clipped to 80 characters, because the line is the alert: a watch usually tails a
870
- build or an error log. A match the agent was busy for does not notify — it is
871
- collected for the next turn instead.
906
+ build or an error log. A match the agent was busy for notifies once that run
907
+ settles, when its wake is raised.
872
908
 
873
909
  ### Delivery method
874
910
 
@@ -908,7 +944,7 @@ suppresses Pi's own `Package Updates Available` block, and draws one notice for
908
944
  every row Pi returned.
909
945
 
910
946
  ```
911
- █▀█ Pi v1.3.0
947
+ █▀█ Pi v1.3.0 ↑1.4.0
912
948
  █▀ █ enhanced by bytefly v0.11.4 ↑0.12.0
913
949
  ```
914
950
 
@@ -924,9 +960,10 @@ The marker is the shared `↑` glyph and this package's newest version — the a
924
960
  is one cell wide, so the header's column math is unchanged — painted with the
925
961
  header's `accent` role: an action rather than a warning, so the muted version
926
962
  beside it stays quiet and the transcript is not turned yellow for a normal state.
927
- Other packages never change the header. The marker is part of the chrome cell, so
928
- the two identity cells still line up, and it is the first thing the identity
929
- sheds when the terminal narrows.
963
+ Pi's own newer version marks the agent line the same way, after `Pi v1.3.0`.
964
+ Other packages never change the header. The marker is part of the identity cell,
965
+ so the two cells still line up, and it is the first thing the identity sheds when
966
+ the terminal narrows.
930
967
 
931
968
  The notice is the shared transcript block: the `bytefly · title` headline at the
932
969
  margin, one rail row per package with this package's version arrow or the other
@@ -934,6 +971,26 @@ package's scope, then the fixing command and this package's release URL, all at
934
971
  `info` severity because nothing is broken. It stays in scrollback and the model
935
972
  reads the same names, version, command, and URL in plain text.
936
973
 
974
+ Pi's own release takes the same route. Pi resolves its newer version from
975
+ `pi.dev` and would draw a bordered `Update Available` block from
976
+ `InteractiveMode.showNewVersionNotification`; bytefly replaces that method, so
977
+ the release Pi already fetched becomes one shared notice and the agent line's
978
+ marker:
979
+
980
+ ```
981
+ bytefly · pi v1.4.0 is available
982
+ ╎ ◌ pi · v1.3.0 → v1.4.0
983
+ ╎ ◌ update · pi update
984
+ ╎ ◌ changelog · https://pi.dev/changelog
985
+ ```
986
+
987
+ That notice is bytefly's rendering, not a second check: Pi makes the request and
988
+ resolves the release, and bytefly reads the same answer, including the release's
989
+ optional `note` as a `release notes` row sanitized to one line. `PI_OFFLINE` and
990
+ `PI_SKIP_VERSION_CHECK` keep their Pi meaning, and a host whose method is missing
991
+ or renamed keeps its own block. The patch is process-wide like the package one,
992
+ installed at `session_start` and restored at `session_shutdown`.
993
+
937
994
  The list is Pi's decision: npm ranges, git refs, project scope, a missing
938
995
  install, and `PI_OFFLINE` all follow its package manager. The only extra read is
939
996
  `GET https://registry.npmjs.org/@gavin-hu%2Fmy-pi-agent/latest` when Pi reports
@@ -984,7 +1041,7 @@ command.
984
1041
  - **The list is a shortlist, not the whole document.** A row is one boolean,
985
1042
  enum, string, or number; the tuning numbers, the labels, and the Pi
986
1043
  preferences `/settings` owns stay in their files, and the catalogue is capped
987
- at fourteen rows so the screen fits a 24-row terminal. `doctor.skip` (an
1044
+ at thirteen rows so the screen fits a 24-row terminal. `doctor.skip` (an
988
1045
  array), the `rates` table, and `price.peak` (a nested object) could never be a
989
1046
  row; the rest are declared JSON-only with their reason in
990
1047
  `test/settings-coverage.test.ts`.
@@ -992,12 +1049,12 @@ command.
992
1049
  because a two-column glyph would push every railed body one cell right; the
993
1050
  loader drops anything else, and the former four-glyph menu is the
994
1051
  configuration reference's example list.
995
- - **`doctor`, `settings`, and `update` are reserved first arguments.**
1052
+ - **`doctor`, `settings`, `skills`, and `update` are reserved first arguments.**
996
1053
  `/bytefly doctor` always selects the report, so an extension literally named
997
- `doctor` cannot be narrowed to by name; `settings` and `update` are reserved
998
- the same way.
999
- - **The picker manages only the `extensions` resource type.** Skills, prompts,
1000
- and themes are handled by Pi's own `pi config`.
1054
+ `doctor` cannot be narrowed to by name; `settings`, `skills`, and `update` are
1055
+ reserved the same way.
1056
+ - **The picker manages the `extensions` and `skills` resource types.** Prompts
1057
+ and themes stay with Pi's own `pi config`.
1001
1058
  - **Built-in extensions are not listed** (`builtin:mcp`, `builtin:codemode`, …):
1002
1059
  their authoritative names are not exposed to extensions. Use `pi config`.
1003
1060
  - **Packages are not installed, removed, or updated here**; use `pi install`,
@@ -1012,16 +1069,19 @@ command.
1012
1069
  package sources; there is no setting for it, and `/bytefly` and `doctor` do not
1013
1070
  report the version. A failed or slow background request is retried by the next
1014
1071
  session, or immediately by `/bytefly update`.
1015
- - **The marker needs the bytefly startup TUI.** It lives on the custom header,
1072
+ - **The markers need the bytefly startup TUI.** They live on the custom header,
1016
1073
  so with `quietStartup` off the notice is the whole signal.
1017
- - **Pi's block is suppressed by a host shim.** bytefly wraps
1018
- `DefaultPackageManager.prototype.checkForAvailableUpdates` at `session_start`
1019
- and restores it on shutdown. A future Pi that changes that method shape makes
1020
- the shim inert, and Pi's own block can come back.
1074
+ - **Pi's blocks are suppressed by host shims.** bytefly wraps
1075
+ `DefaultPackageManager.prototype.checkForAvailableUpdates` and
1076
+ `InteractiveMode.prototype.showNewVersionNotification` at `session_start` and
1077
+ restores both on shutdown. A future Pi that changes either method shape makes
1078
+ that shim inert, and Pi's own block can come back.
1021
1079
  - **No auto-update, and the release URL is text only.** The notice names a
1022
1080
  command instead of running one, and the notice renderer cannot open a link, so
1023
1081
  the release row prints the URL and nothing more — no changelog body, no way to
1024
- click through from the transcript.
1082
+ click through from the transcript. Pi's optional release note arrives as one
1083
+ sanitized `release notes` row, so a multi-paragraph note is flattened and
1084
+ clipped at the width.
1025
1085
  - **Project toggles are two-state per press** (`enable`/`disable`). `x` clears
1026
1086
  the override, which is the third state; a resource with no project entry in
1027
1087
  `pi config` is still managed there.
@@ -1037,7 +1097,10 @@ command.
1037
1097
  Anthropic's 2× one-hour cache write are not modelled; switch to `USD` mode
1038
1098
  to use Pi's recorded cost for those models.
1039
1099
  - **No FX conversion.** The two modes are separate methods; neither converts
1040
- one currency into the other. A model is priced only by the selected method.
1100
+ one currency into the other. A model is priced only by the selected method. A
1101
+ `CNY` session names the records it could not price instead of silently leaving
1102
+ them out — switch to `USD` for Pi's per-model cost, or add yuan `price.rates`
1103
+ entries for the models you use.
1041
1104
  - **Two built-in footer indicators cannot be reproduced.** Pi's `(auto)` marks
1042
1105
  that auto-compaction is on, and its `(sub)` marks a subscription-backed
1043
1106
  provider. Auto-compaction is session state on Pi's own session object, and
@@ -1113,7 +1176,7 @@ rather than showing a wrong value.
1113
1176
 
1114
1177
  | Integration point | Details |
1115
1178
  |---|---|
1116
- | Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **Bytefly startup TUI** row). `false`, `"header"`, and unset call `setHeader(undefined)`, leaving Pi's built-in header in place. The nameplate insets by Pi's `outputPad` (read through `pi.getSettings()`), so it sits on the transcript margin, and the help hangs one body indent inside it. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. The factory reads `tui.terminal.rows` on every render, so the height ladder in `header/config.ts` sheds help groups and then the leading blank row as the terminal shortens (unknown height keeps the full header). The chrome version gains `↑<latest>` from the `UpdateSource`, and `registerHeader` returns a `refresh()` handle that re-installs the last context's header when that value arrives. |
1179
+ | Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **Bytefly startup TUI** row). `false`, `"header"`, and unset call `setHeader(undefined)`, leaving Pi's built-in header in place. The nameplate insets by Pi's `outputPad` (read through `pi.getSettings()`), so it sits on the transcript margin, and the help hangs one body indent inside it. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. The factory reads `tui.terminal.rows` on every render, so the height ladder in `header/config.ts` sheds help groups and then the leading blank row as the terminal shortens (unknown height keeps the full header). The chrome version gains `↑<latest>` from the `UpdateSource`, the agent line gains Pi's own `↑<latest>` from the second store, and `registerHeader` returns a `refresh()` handle that re-installs the last context's header when either value arrives. |
1117
1180
  | Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
1118
1181
  | User message | `pi.registerMarkdownTransformer` puts a two-row `You` nameplate (the label over a full-width rule) above each user message; one padded level-2 heading carries the accent through `mdHeading` for both rows, and the shipped themes set `userMessageBg` to the terminal default, so the block has no fill. Pi renders the result as Markdown, so the surface adds no component or color of its own. |
1119
1182
  | Notice | `registerMessageRenderer(NOTICE_TYPE)` draws every shared transcript notice at the margin from its `details`; the headline stays at the margin with its title painted by the notice's own severity, and its rows hang from the transcript rail, painted by the notice's worst severity, whose glyph comes from the shared `RailSource`. `job` and `watch` post one when their work settles, and `doctor` posts one at `session_start` for a missing hard requirement. The type and shape come from `lib/notice.ts`. A message without `details` falls back to Pi's default custom-message box. |
@@ -1128,11 +1191,12 @@ rather than showing a wrong value.
1128
1191
  | Doctor tool | `pi.registerTool("run_doctor")`, read-only (`readOnlyHint: true`, `openWorldHint: false`), direct exposure and active on registration (the defaults, so not declared), with a typed `outputSchema` mirroring `structuredContent`. Its `readOnlyHint` is what the shared default-deny policy in `lib/policy.ts` reads to allow it in plan mode. |
1129
1192
  | Doctor probes | `run_doctor` and the screen share the session cache created by `registerDoctor`; the screen mounts on that cache and probes on the first Extensions view (the command's `refresh` forces it), while the text modes probe before printing, and `/bytefly refresh` and `refresh: true` re-probe. Probes spawn `<binary> --version`, lazily import optional packages, and read config files through `lib/requirements.ts`; nothing is ever written. |
1130
1193
  | Status routing | Reads `footerData.getExtensionStatuses()` (a custom footer replaces the built-in one entirely); `worktree` routes to line 1, plan/alert statuses to line 2's trailing slot. |
1194
+ | Release notice | `session_start` in `tui` mode patches `InteractiveMode.prototype.showNewVersionNotification` through the shared `patchPrototypeMethod`, so the release Pi resolved becomes `pi.sendMessage(piReleaseNotice(...))` under the shared notice type and `paintLatest` records its version for the agent line's marker (`onUpdate` re-installs the header). The callback posts once per load and only while the session is live; a throw calls the captured original, so Pi's own box is the fallback. `session_shutdown` restores the method and clears the marker. |
1131
1195
  | Update check | `session_start` in `tui` mode installs a suppression on `DefaultPackageManager.prototype.checkForAvailableUpdates`, then reads `<agentDir>/bytefly/update.json`. A fresh entry whose key matches the cwd and effective package sources is recorded without a package-manager call; otherwise bytefly fires `fetchAvailableUpdates()` without awaiting, resolves this package's version through `fetchLatestVersion()` when Pi reports it, writes the snapshot, and records it. `onUpdate` re-installs the header, and `pi.sendMessage(updateNotice(...))` posts the one notice with its version arrow and release URL. `PI_OFFLINE` paints the cached marker only. `/bytefly update` calls the returned `UpdateHandle.recheck()`, which bypasses the window and returns an `UpdateOutcome`; a generation counter drops a background reply that lands after `session_shutdown`, a per-load flag keeps it to one announcement, and shutdown restores Pi's method. |
1132
1196
  | Config | `bytefly.json` from the agent directory and `<cwd>/.pi`; the `price` section is read once per footer install (a new session or a session-tree change), the `notify` and `doctor` sections at `session_start`, and the `chrome` section's rail glyph at `session_start`/`session_tree`. Nothing watches the document. The update check has no section: it is on whenever `PI_OFFLINE` is off, and its 24 h window is not configurable. |
1133
1197
  | Data sources | `footerData.getGitBranch()`, `footerData.getAvailableProviderCount()`, `ctx.getContextUsage()`, `ctx.sessionManager.getEntries()`, `ctx.sessionManager.getSessionName()`, `ctx.model`; subscribes to `footerData.onBranchChange` to repaint. |
1134
- | State storage | None besides the inert separator entries. The footer reads session entries and the price config (a memoized scan) and writes no tool-result `details`; it appends `bytefly-separator` entries excluded from LLM context. The screen derives its view from the picker runtime and the current reports, and persists extension toggles through `settings.json`. The Settings section derives from a snapshot of the personal `settings.json` and both `bytefly.json` documents, and persists through the same `SettingsManager` setters or the per-leaf `bytefly.json` writer. Doctor's findings are session-scoped in memory only — cached for the session, never written to the session or a file. Notify holds only the config and the run-active flag in its closure. The update check holds this package's version in the per-load `UpdateSource` and one project-scoped snapshot in `<agentDir>/bytefly/update.json`. |
1135
- | Lifecycle | `session_start` installs the header when Pi's `quietStartup` is `true` and the footer, loads the chrome rail glyph, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on and `quietStartup` is `true`, loads the notify config and subscribes to the job bus, and starts the package-update check; `session_tree` reinstalls the header and footer and reloads the rail; `session_shutdown` restores Pi's built-in header, footer, and package-update method, disposes the branch subscription, drops doctor's cached findings, drops the notify bus subscription, and clears the recorded version. |
1198
+ | State storage | None besides the inert separator entries. The footer reads session entries and the price config (a memoized scan) and writes no tool-result `details`; it appends `bytefly-separator` entries excluded from LLM context. The screen derives its view from the picker runtime, the current reports, and the skill index, and persists extension and skill toggles through `settings.json`. The Settings section derives from a snapshot of the personal `settings.json` and both `bytefly.json` documents, and persists through the same `SettingsManager` setters or the per-leaf `bytefly.json` writer. Doctor's findings are session-scoped in memory only — cached for the session, never written to the session or a file. Notify holds only the config and the run-active flag in its closure. The update check holds this package's version in the per-load `UpdateSource` and one project-scoped snapshot in `<agentDir>/bytefly/update.json`. |
1199
+ | Lifecycle | `session_start` installs the header when Pi's `quietStartup` is `true` and the footer, loads the chrome rail glyph, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on and `quietStartup` is `true`, loads the notify config and subscribes to the job bus, and starts the package-update check; `session_tree` reinstalls the header and footer and reloads the rail; `session_shutdown` restores Pi's built-in header, footer, package-update method, and release-notice method, disposes the branch subscription, drops doctor's cached findings, drops the notify bus subscription, and clears the recorded versions. |
1136
1200
 
1137
1201
  ## Design notes
1138
1202
 
@@ -1389,18 +1453,19 @@ calculation), `message/` (the user-message marker), `notice/` (the shared notice
1389
1453
  run line on Pi's working row), `panel/` (the
1390
1454
  unified screen and its merged model),
1391
1455
  `picker/` (discovery and the settings store), `doctor/` (the `run_doctor` tool
1392
- and its probe runtime), `notify/`, and `update/` (Pi's package list, the host
1393
- suppression, the cache, and the header marker). The chrome and the screen are drawn from
1456
+ and its probe runtime), `notify/`, and `update/` (Pi's package list, Pi's own
1457
+ release notice, the host patches, the cache, and the header markers). The chrome and the screen are drawn from
1394
1458
  the package's [`lib/tui/`](../../lib/tui/) design system (tokens, rules, rows,
1395
1459
  columns, gauge), so the look follows the active theme.
1396
1460
 
1397
1461
  | File | Responsibility |
1398
1462
  |---|---|
1399
- | `index.ts` | Composition root: the disable guard, the eleven `register*` calls, the one shared output-pad store, and the rail source. |
1463
+ | `index.ts` | Composition root: the disable guard, the `register*` calls, the two per-load update stores, the one shared output-pad store, and the rail source. |
1400
1464
  | `pad.ts` | `PadSource` and `createPadStore`: one record of Pi's output pad, so the tool frame, the notice, and the turn separator inset by the same margin. |
1401
1465
  | `chrome.ts` | The transcript rail (`RAIL_ROLES`, `railGlyph`), the `chrome` section's normalizer and loader, and the `RailSource` that `registerChrome` keeps current on `session_start`/`session_tree`. |
1402
1466
  | `header/config.ts` | Header tuning (`HEADER_CONFIG`): mark and identity roles, tagline, and the grouped help entries. |
1403
- | `header/component.ts` | `ByteflyHeader`: the mark, identity rows, signature rule, and grouped help, plus its factory. |
1467
+ | `header/component.ts` | `ByteflyHeader`: the mark, the two identity rows mounted from `identityCells`, signature rule, and grouped help, plus its factory. |
1468
+ | `header/identity.ts` | `IdentityInput` and `identityCells`: the agent and chrome cells, each with its `↑` marker, in the ladder that sheds the chrome marker, the chrome version, the chrome line, and finally the agent's marker with the row. |
1404
1469
  | `header/register.ts` | Installs/restores the header and owns its session lifecycle. |
1405
1470
  | `footer/register.ts` | Installs/restores the footer and owns its session lifecycle. |
1406
1471
  | `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, status keys, labels. |
@@ -1411,7 +1476,8 @@ columns, gauge), so the look follows the active theme.
1411
1476
  | `footer/price/config.ts` | The `price` section of `bytefly.json`: schema, defaults, built-in DeepSeek rates/tariff, currency defaults, normalizer, loader. |
1412
1477
  | `footer/price/rates.ts` | Model-key matching: `createRateLookup` splits every key once, splits a key at its first slash (so an OpenRouter model id may contain one), matches exact and wildcard most-specific-first, and remembers the last record's model. |
1413
1478
  | `footer/price/schedule.ts` | Peak-window parsing and evaluation in a configured zone. |
1414
- | `footer/price/price.ts` | Records → totals: rated cost in both modes, Pi's recorded cost as USD's fallback, and the peak multiplier. |
1479
+ | `footer/price/price.ts` | Records → totals: rated cost in both modes, Pi's recorded cost as USD's fallback, the peak multiplier, and the count of records CNY could not rate. |
1480
+ | `footer/unpriced.ts` | The one notice a CNY session posts for records it could not price, and its OS-notification body. |
1415
1481
  | `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd, the context role, truncation). |
1416
1482
  | `footer/render/status.ts` | Status-chip transforms: `compactStatus` and `dropStatusDetail`. |
1417
1483
  | `footer/render/segments.ts` | The segment builders: forms, weights, separators, roles. |
@@ -1420,7 +1486,7 @@ columns, gauge), so the look follows the active theme.
1420
1486
  | `footer/render/footer.ts` | `StatusBar` component and footer factory. |
1421
1487
  | `message/config.ts` | Nameplate tuning (`MESSAGE_CONFIG`): the label and the rule. |
1422
1488
  | `message/format.ts` | Pure `nameplate` and `styleUserMessage`: the two-row nameplate (label over a full-width rule) and its placement above the message. |
1423
- | `message/register.ts` | Registers the Markdown transformer. |
1489
+ | `message/register.ts` | Registers the Markdown transformer (the nameplate). |
1424
1490
  | `notice/config.ts` | Notice tuning (`NOTICE_CONFIG`): source/title/detail roles, the severity glyphs and roles, the shared rail roles, and the item cap. |
1425
1491
  | `notice/component.ts` | Pure `noticeLines` and `NoticeComponent`: the headline at the margin, the rail-led severity rows, sanitized and width-clipped. |
1426
1492
  | `notice/register.ts` | Registers the message renderer for the shared notice type and hands it the rail source. |
@@ -1436,19 +1502,29 @@ columns, gauge), so the look follows the active theme.
1436
1502
  | `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the words, the tool singular/plural, and the tick interval. |
1437
1503
  | `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape: the plain count and the `tool · N tools · elapsed` run line. |
1438
1504
  | `working/register.ts` | Starts the tick on `turn_start`, tracks top-level tools on `tool_execution_start`, and cancels on `agent_end`/`session_shutdown`. |
1439
- | `panel/types.ts` | `PanelSection` (`extensions` | `settings`), `PanelRow`, and `PanelModel`, the merged row model. |
1440
- | `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering. |
1441
- | `panel/format.ts` | Non-TUI text: the extension headline and grouped listing with a per-row health suffix, plus the section segments, the Settings counts/headline, and the flat Settings listing. |
1442
- | `panel/settings.ts` | The curated Settings catalogue: the fourteen descriptors in screen order, snapshot views and origins, value cycling, stored-value mapping, validation, plus the per-section readers that resolve a row's leaf over the global and project documents. |
1505
+ | `panel/types.ts` | `PanelSection` (`extensions` | `skills` | `settings`), `PanelRow` with its optional skill info, `SkillInfo`, and `PanelModel`, the merged row model. |
1506
+ | `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering; the skills model that labels rows from `SKILL.md`. |
1507
+ | `panel/format.ts` | Non-TUI text: the resource headline and grouped listing with a per-row verdict, the section segments and their order, the Settings counts/headline, and the flat Settings listing. |
1508
+ | `panel/settings.ts` | The curated Settings catalogue: the thirteen descriptors in screen order, snapshot views and origins, value cycling, stored-value mapping, validation, plus the per-section readers that resolve a row's leaf over the global and project documents. |
1443
1509
  | `panel/settings-runtime.ts` | The Settings runtime: snapshot cache, scope guards, app setters, per-leaf `bytefly.json` writes, dirty state, and change listeners. |
1444
1510
  | `panel/themes.ts` | Which themes the Theme row offers: the host's resolved list narrowed to the palettes under this package's `themes/`, identified by directory rather than name. |
1445
- | `panel/tui.ts` | `PanelComponent`, the two-section dock screen (Extensions list and Settings list) and its section composition; the editing key map is `tui/editing.ts` and the shared frame is `tui/frame.ts`. |
1446
- | `panel/commands.ts` | `/bytefly`: one command for the screen sections, the `doctor` report, the settings listing, and their text modes. |
1447
- | `picker/types.ts` | Picker host seams (`SettingsStore`, `ExtensionResolver`, `Discovery`), the app-settings setters, and row types. |
1448
- | `picker/resources.ts` | Pure grouping, labels, display names, and pattern helpers. |
1511
+ | `panel/skills.ts` | Skill metadata through Pi's own `loadSkills`, keyed by resolved path, plus the deduplicated paths both discovery views read. |
1512
+ | `panel/tui.ts` | `PanelComponent`, the three-section dock screen: the section switch, the cursors, the toggle chain, and the two list sections through one `LIST_VIEWS` table. |
1513
+ | `panel/tui/list-view.ts` | The shared list grammar: the section headline, one resource row, and the key-hint row both sections offer. |
1514
+ | `panel/tui/extensions-view.ts` | The Extensions detail pane: the doctor's findings, including the resource path when a row has no verdict. |
1515
+ | `panel/tui/skills-view.ts` | The Skills detail pane: the path, the description, and Pi's refusal. |
1516
+ | `panel/tui/settings-view.ts` | The Settings rows, the value's source and description pane, the JSON pane, and the editing cell. |
1517
+ | `panel/tui/entries.ts` | The flat display entries per section and the stable focus keys. |
1518
+ | `panel/tui/editing.ts` | The text-row editor's key map: caret moves, delete, clear, commit, cancel. |
1519
+ | `panel/tui/frame.ts` | The shared dock frame, the section bar, the detail-row budget, and the optional rows that give way on a short terminal. |
1520
+ | `panel/tui/settings-section.ts` | The Settings section's editor and JSON-pane state, its key handling, and the screen it draws. |
1521
+ | `panel/tui/nav.ts` | The panel's cursor arithmetic and one read of a navigation key. |
1522
+ | `panel/commands.ts` | `/bytefly`: one command for the screen sections, the `doctor` report, the settings and skills listings, and their text modes. |
1523
+ | `picker/types.ts` | Picker host seams (`SettingsStore`, `ResourceResolver`, `Discovery`, `ResourceKind`), the app-settings setters, and row types. |
1524
+ | `picker/resources.ts` | Pure grouping, labels, display names per resource kind, and pattern helpers. |
1449
1525
  | `picker/toggle.ts` | Pure next-settings transforms for global and project toggles. |
1450
- | `picker/discovery.ts` | Host wiring: builds the global and effective views from Pi's managers, and the two settings stores for the settings-only command path. |
1451
- | `picker/runtime.ts` | Picker scope, live view copies, dirty tracking, and persistence. |
1526
+ | `picker/discovery.ts` | Host wiring: builds both kinds' global and effective views from Pi's managers, and the two settings stores for the settings-only command path. |
1527
+ | `picker/runtime.ts` | Picker scope, live view copies, dirty tracking, and persistence, for both resource kinds through one ops table. |
1452
1528
  | `doctor/register.ts` | Registers `run_doctor` and the proactive session-start check; returns the runtime. |
1453
1529
  | `doctor/runtime.ts` | Host seams, the session cache, and the two probe modes. |
1454
1530
  | `doctor/tools.ts` | The `run_doctor` tool and its renderers. |
@@ -1460,14 +1536,16 @@ columns, gauge), so the look follows the active theme.
1460
1536
  | `notify/dispatch.ts` | Method selection and delivery: OSC 777/99, Windows toast, `osascript`, `notify-send`, over injected seams. |
1461
1537
  | `notify/format.ts` | Pure notification text: session label and the turn / input / job / watch bodies. |
1462
1538
  | `notify/register.ts` | Registers the four triggers, loads the config at `session_start`, and owns the job- and watch-bus subscriptions. |
1463
- | `update/types.ts` | `PackageUpdate`, derived from Pi's public manager method, and `PackageUpdateCheck`. |
1464
- | `update/suppress.ts` | The host shim: capture Pi's `checkForAvailableUpdates`, replace it with an empty result, and restore it on shutdown. |
1539
+ | `update/types.ts` | `PackageUpdate` and `PackageUpdateCheck`, derived from Pi's public manager method; `PiRelease` and `ReleaseNoticePrototype`, derived from Pi's notification method. |
1540
+ | `update/patch.ts` | `patchPrototypeMethod`: the one host-method replacement both update surfaces use — a per-method `Symbol.for` marker, idempotent reuse, a restore that only puts back its own replacement, and an inert result when the host has no such method. |
1541
+ | `update/suppress.ts` | The two host shims over `patchPrototypeMethod`: capture Pi's `checkForAvailableUpdates` and replace it with an empty result, and hand `showNewVersionNotification`'s release to bytefly (falling back to the captured original if that throws). |
1465
1542
  | `update/check.ts` | Pi's package list through `DefaultPackageManager`, plus the registry `GET` that names this package's version for the marker, arrow, and release URL. |
1466
1543
  | `update/version.ts` | Pure semver parsing and `isNewerVersion`, including prerelease precedence. |
1467
- | `update/state.ts` | `UpdateSource` and `createUpdateState` (this package's known version, one record per load), plus `UpdateOutcome`, the four answers an explicit re-check can give. |
1544
+ | `update/state.ts` | `UpdateSource` and `createUpdateState` (one known version per subject per load), `paintLatest` (record and repaint the header only on a change), plus `UpdateOutcome`, the four answers an explicit re-check can give. |
1468
1545
  | `update/cache.ts` | The project-scoped snapshot: `<agentDir>/bytefly/update.json`, the cwd/package key, the 24 h window in `isFresh`, a validated read that degrades to a miss, and the atomic write. |
1469
- | `update/format.ts` | `updateMarker`, `updateNotice`, `releaseUrl`, and `updateOutcomeText`: the header's `↑0.12.0`, the multi-package notice, and the one line `/bytefly update` prints. |
1470
- | `update/register.ts` | The lifecycle: suppression, the cache-first session-start read, the async package-manager call, this package's version lookup, the `PI_OFFLINE` and `tui` gates, the once-per-load announcement, the shutdown generation guard, and the `recheck()` handle `/bytefly update` calls. |
1546
+ | `update/format.ts` | `updateMarker`, `updateNotice`, `releaseUrl`, `updateOutcomeText`, and `piReleaseNotice`, plus the shared command/link rows: the header's `↑0.12.0`, the multi-package notice, the line `/bytefly update` prints, and the notice that replaces Pi's `Update Available` box. |
1547
+ | `update/register.ts` | The package-update lifecycle: suppression, the cache-first session-start read, the async package-manager call, this package's version lookup, the `PI_OFFLINE` and `tui` gates, the once-per-load announcement, the shutdown generation guard, and the `recheck()` handle `/bytefly update` calls. |
1548
+ | `update/release.ts` | Pi's own release lifecycle: install the notification patch in `tui` mode, record the release's version for the agent-line marker, post the notice once per load while the session is live, and restore the method on shutdown. |
1471
1549
 
1472
1550
  ## Testing
1473
1551
 
@@ -1499,10 +1577,12 @@ transforms (`picker/toggle`), discovery with an injected factory
1499
1577
  unified screen is covered by its pure model merge (`panel/join`), its text
1500
1578
  formatter (`panel/format`), the settings catalogue and its cycling
1501
1579
  (`panel/settings`), the scope-aware settings runtime (`panel/settings-runtime`,
1502
- including a nested leaf write that keeps its siblings),
1503
- the screen's rendering (`panel/tui`), its editing key map (`tui/editing`),
1504
- the shared frame (`tui/frame`), and the command through
1505
- the bytefly factory (`panel/commands`).
1580
+ including a nested leaf write that keeps its siblings), the skill metadata join
1581
+ and loader (`panel/skills`, on real `SKILL.md` files),
1582
+ the screen's rendering (`panel/tui`), its list grammar (`tui/list-view`), the
1583
+ Skills pane (`tui/skills-view`), the Settings section state (`tui/settings-section`),
1584
+ its editing key map (`tui/editing`), the shared frame (`tui/frame`), and the
1585
+ command through the bytefly factory (`panel/commands`).
1506
1586
  The doctor surface is covered by its pure report
1507
1587
  formatting (`doctor/format`), its config loader (`doctor/config`), and
1508
1588
  registration, the proactive notice, the session cache, and `run_doctor`