@gavin-hu/my-pi-agent 0.17.0 → 0.19.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.
- package/README.md +61 -45
- package/README.zh-CN.md +54 -42
- package/docs/extensions/README.md +34 -0
- package/docs/extensions/board.md +344 -0
- package/{extensions/bytefly/README.md → docs/extensions/bytefly.md} +465 -416
- package/{extensions/check/README.md → docs/extensions/check.md} +83 -68
- package/{extensions/context/README.md → docs/extensions/context.md} +40 -23
- package/docs/extensions/file-browse.md +554 -0
- package/{extensions/file-open/README.md → docs/extensions/file-open.md} +31 -23
- package/{extensions/file-read/README.md → docs/extensions/file-read.md} +47 -55
- package/{extensions/goal/README.md → docs/extensions/goal.md} +115 -131
- package/{extensions/job/README.md → docs/extensions/job.md} +66 -53
- package/{extensions/memory/README.md → docs/extensions/memory.md} +74 -63
- package/docs/extensions/plan.md +976 -0
- package/{extensions/question/README.md → docs/extensions/question.md} +54 -28
- package/{extensions/rewind/README.md → docs/extensions/rewind.md} +115 -122
- package/docs/extensions/session-bus.md +285 -0
- package/{extensions/subagent/README.md → docs/extensions/subagent.md} +166 -119
- package/docs/extensions/team.md +226 -0
- package/{extensions/todo/README.md → docs/extensions/todo.md} +85 -88
- package/{extensions/watch/README.md → docs/extensions/watch.md} +60 -38
- package/{extensions/web-access/README.md → docs/extensions/web-access.md} +93 -50
- package/{extensions/wechat/README.md → docs/extensions/wechat.md} +275 -192
- package/{extensions/worktree/README.md → docs/extensions/worktree.md} +115 -72
- package/extensions/board/commands.ts +87 -0
- package/extensions/board/config.ts +36 -0
- package/extensions/board/format.ts +72 -0
- package/extensions/board/index.ts +40 -0
- package/extensions/board/input.ts +54 -0
- package/extensions/board/join.ts +42 -0
- package/extensions/board/page.ts +312 -0
- package/extensions/board/result.ts +99 -0
- package/extensions/board/rows.ts +48 -0
- package/extensions/board/schema.ts +75 -0
- package/extensions/board/seat.ts +29 -0
- package/extensions/board/snapshot.ts +41 -0
- package/extensions/board/tools.ts +279 -0
- package/extensions/board/transport/router.ts +172 -0
- package/extensions/board/transport/server.ts +149 -0
- package/extensions/board/types.ts +54 -0
- package/extensions/board/view/actions.ts +306 -0
- package/extensions/board/view/client.ts +41 -0
- package/extensions/board/view/keys.ts +121 -0
- package/extensions/board/view/live.ts +397 -0
- package/extensions/board/view/page.ts +158 -0
- package/extensions/board/view/render.ts +496 -0
- package/extensions/board/view/styles.ts +211 -0
- package/extensions/board/view/team.ts +305 -0
- package/extensions/board/writes.ts +99 -0
- package/extensions/bytefly/notify/types.ts +1 -1
- package/extensions/bytefly/panel/commands.ts +40 -7
- package/extensions/bytefly/panel/settings-runtime.ts +0 -6
- package/extensions/bytefly/panel/settings.ts +11 -21
- package/extensions/bytefly/panel/tui/settings-view.ts +1 -1
- package/extensions/bytefly/picker/discovery.ts +0 -2
- package/extensions/bytefly/picker/types.ts +0 -2
- package/extensions/bytefly/update/check.ts +39 -0
- package/extensions/bytefly/update/format.ts +15 -0
- package/extensions/bytefly/update/register.ts +73 -34
- package/extensions/bytefly/update/state.ts +6 -3
- package/extensions/context/tui.ts +1 -1
- package/extensions/file-browse/{config.ts → config/config.ts} +13 -4
- package/extensions/file-browse/{files.ts → files/files.ts} +1 -14
- package/extensions/file-browse/{paths.ts → files/paths.ts} +1 -1
- package/extensions/file-browse/{git.ts → git/git.ts} +10 -3
- package/extensions/file-browse/index.ts +4 -4
- package/extensions/file-browse/{live.ts → live/live.ts} +54 -82
- package/extensions/file-browse/live/rev.ts +42 -0
- package/extensions/file-browse/{router.ts → transport/router.ts} +44 -17
- package/extensions/file-browse/transport/server.ts +110 -0
- package/extensions/file-browse/view/chrome.ts +83 -0
- package/extensions/file-browse/{client.ts → view/client.ts} +63 -1
- package/extensions/file-browse/view/diff-html.ts +94 -0
- package/extensions/file-browse/{html.ts → view/html.ts} +32 -158
- package/extensions/file-browse/{icons.ts → view/icons.ts} +1 -1
- package/extensions/file-browse/{live-client.ts → view/live-client.ts} +47 -1
- package/extensions/file-browse/{markdown.ts → view/markdown.ts} +7 -7
- package/extensions/file-browse/{raw-html.ts → view/raw-html.ts} +1 -1
- package/extensions/file-browse/{styles.ts → view/styles.ts} +31 -5
- package/extensions/file-browse/{tree.ts → view/tree.ts} +1 -1
- package/extensions/file-browse/{urls.ts → view/urls.ts} +1 -1
- package/extensions/file-read/schema.ts +2 -1
- package/extensions/goal/plan-route.ts +8 -2
- package/extensions/job/index.ts +15 -7
- package/extensions/memory/store.ts +12 -5
- package/extensions/plan/blocks.ts +23 -2
- package/extensions/plan/commands.ts +77 -21
- package/extensions/plan/feedback.ts +409 -63
- package/extensions/plan/index.ts +7 -5
- package/extensions/plan/plan-index.ts +44 -10
- package/extensions/plan/plan-text.ts +51 -24
- package/extensions/plan/plans.ts +162 -57
- package/extensions/plan/policy.ts +20 -12
- package/extensions/plan/review-prompt.ts +93 -0
- package/extensions/plan/review.ts +51 -95
- package/extensions/plan/runtime.ts +22 -10
- package/extensions/plan/sections.ts +112 -0
- package/extensions/plan/steps.ts +63 -95
- package/extensions/plan/tools/enter.ts +8 -3
- package/extensions/plan/tools/exit.ts +13 -19
- package/extensions/plan/tools/write.ts +8 -3
- package/extensions/plan/tools.ts +1 -1
- package/extensions/plan/tui.ts +29 -15
- package/extensions/plan/types.ts +29 -3
- package/extensions/plan/web-chrome.ts +2 -1
- package/extensions/plan/web-client.ts +122 -178
- package/extensions/plan/web-collab.ts +207 -0
- package/extensions/plan/web-comments.ts +269 -0
- package/extensions/plan/web-page.ts +96 -17
- package/extensions/plan/web-router.ts +109 -47
- package/extensions/plan/web-share-session.ts +191 -0
- package/extensions/plan/web-share.ts +169 -0
- package/extensions/plan/web-streams.ts +124 -0
- package/extensions/plan/web-tokens.ts +63 -0
- package/extensions/plan/web.ts +245 -151
- package/extensions/question/dialogs.ts +91 -1
- package/extensions/question/tools.ts +2 -1
- package/extensions/rewind/{commands.ts → commands/commands.ts} +5 -5
- package/extensions/rewind/{review.ts → commands/review.ts} +13 -13
- package/extensions/rewind/{rewind.ts → commands/rewind.ts} +6 -6
- package/extensions/rewind/{config.ts → config/config.ts} +1 -1
- package/extensions/rewind/index.ts +3 -3
- package/extensions/rewind/{policy.ts → state/policy.ts} +4 -4
- package/extensions/rewind/{runtime.ts → state/runtime.ts} +11 -11
- package/extensions/rewind/{snapshot-run.ts → state/snapshot-run.ts} +1 -1
- package/extensions/rewind/{timeline.ts → state/timeline.ts} +2 -2
- package/extensions/rewind/{format.ts → text/format.ts} +3 -3
- package/extensions/rewind/{git.ts → transport/git.ts} +2 -2
- package/extensions/rewind/{restore.ts → transport/restore.ts} +2 -2
- package/extensions/rewind/{snapshot.ts → transport/snapshot.ts} +1 -1
- package/extensions/rewind/{store.ts → transport/store.ts} +1 -1
- package/extensions/rewind/{checklist.ts → view/checklist.ts} +6 -6
- package/extensions/rewind/{hunk-picker.ts → view/hunk-picker.ts} +8 -8
- package/extensions/rewind/{path-picker.ts → view/path-picker.ts} +7 -7
- package/extensions/rewind/{review-tui.ts → view/review-tui.ts} +11 -11
- package/extensions/rewind/{rewind-tui.ts → view/rewind-tui.ts} +17 -11
- package/extensions/rewind/{status.ts → view/status.ts} +4 -4
- package/extensions/session-bus/commands.ts +113 -0
- package/extensions/session-bus/format.ts +101 -0
- package/extensions/session-bus/index.ts +75 -0
- package/extensions/session-bus/join-request.ts +40 -0
- package/extensions/session-bus/mail-watch.ts +134 -0
- package/extensions/session-bus/notice.ts +86 -0
- package/extensions/session-bus/overlap.ts +36 -0
- package/extensions/session-bus/protocol.ts +104 -0
- package/extensions/session-bus/resolve.ts +67 -0
- package/extensions/session-bus/result.ts +208 -0
- package/extensions/session-bus/rows.ts +171 -0
- package/extensions/session-bus/runtime.ts +466 -0
- package/extensions/session-bus/store.ts +365 -0
- package/extensions/session-bus/tools.ts +192 -0
- package/extensions/session-bus/tui.ts +394 -0
- package/extensions/session-bus/types.ts +98 -0
- package/extensions/subagent/agents.ts +9 -8
- package/extensions/subagent/invocation.ts +4 -2
- package/extensions/team/commands.ts +112 -0
- package/extensions/team/dispatch.ts +133 -0
- package/extensions/team/format.ts +105 -0
- package/extensions/team/index.ts +33 -0
- package/extensions/team/schema.ts +29 -0
- package/extensions/team/tools.ts +246 -0
- package/extensions/team/types.ts +48 -0
- package/extensions/watch/index.ts +15 -9
- package/extensions/web-access/fetch/page.ts +4 -1
- package/extensions/web-access/fetch/structured.ts +447 -0
- package/extensions/web-access/fetch/tool.ts +2 -1
- package/extensions/web-access/search/tool.ts +2 -1
- package/extensions/wechat/bridge.ts +76 -92
- package/extensions/wechat/{commands.ts → commands/commands.ts} +26 -18
- package/extensions/wechat/{doctor.ts → commands/doctor.ts} +5 -5
- package/extensions/wechat/{history.ts → commands/history.ts} +1 -1
- package/extensions/wechat/{login.ts → commands/login.ts} +3 -3
- package/extensions/wechat/{slash.ts → commands/slash.ts} +38 -2
- package/extensions/wechat/dialog/channels.ts +136 -0
- package/extensions/wechat/{interaction.ts → dialog/interaction.ts} +66 -51
- package/extensions/wechat/{prompt.ts → dialog/prompt.ts} +40 -25
- package/extensions/wechat/{remote-ui.ts → dialog/remote-ui.ts} +1 -1
- package/extensions/wechat/index.ts +10 -10
- package/extensions/wechat/{admission.ts → peer/admission.ts} +2 -2
- package/extensions/wechat/{peer-session.ts → peer/peer-session.ts} +2 -2
- package/extensions/wechat/{peer-worker.ts → peer/peer-worker.ts} +119 -56
- package/extensions/wechat/{presence.ts → peer/presence.ts} +11 -11
- package/extensions/wechat/{reply-pipeline.ts → peer/reply-pipeline.ts} +13 -5
- package/extensions/wechat/{credentials.ts → state/credentials.ts} +2 -2
- package/extensions/wechat/{state.ts → state/state.ts} +14 -2
- package/extensions/wechat/{format.ts → text/format.ts} +3 -3
- package/extensions/wechat/{notices.ts → text/notices.ts} +15 -7
- package/extensions/wechat/tools.ts +29 -12
- package/extensions/wechat/{client.ts → transport/client.ts} +26 -2
- package/extensions/wechat/{deliver.ts → transport/deliver.ts} +104 -40
- package/extensions/wechat/{inbound.ts → transport/inbound.ts} +5 -5
- package/extensions/wechat/{media.ts → transport/media.ts} +11 -5
- package/extensions/wechat/transport/outbound.ts +142 -0
- package/extensions/wechat/{poll.ts → transport/poll.ts} +3 -3
- package/extensions/wechat/types.ts +10 -1
- package/extensions/wechat/{login-screen.ts → view/login-screen.ts} +4 -4
- package/extensions/wechat/{status-screen.ts → view/status-screen.ts} +31 -26
- package/extensions/worktree/git.ts +5 -0
- package/extensions/worktree/guard.ts +3 -5
- package/extensions/worktree/registry.ts +11 -5
- package/extensions/worktree/status.ts +1 -3
- package/lib/README.md +12 -6
- package/lib/board/card.ts +290 -0
- package/lib/board/links.ts +117 -0
- package/lib/board/page-pointer.ts +256 -0
- package/lib/board/round-text.ts +72 -0
- package/lib/board/round.ts +89 -0
- package/lib/board/rules.ts +304 -0
- package/lib/board/session.ts +105 -0
- package/lib/board/store.ts +310 -0
- package/lib/board/view.ts +150 -0
- package/lib/errors.ts +12 -4
- package/lib/format.ts +13 -0
- package/lib/http/guard.ts +112 -0
- package/lib/http/index.ts +16 -5
- package/lib/http/router.ts +40 -13
- package/lib/http/serve.ts +234 -0
- package/lib/http/server.ts +29 -13
- package/lib/http/sink.ts +110 -0
- package/lib/http/token.ts +38 -0
- package/lib/interaction.ts +10 -0
- package/lib/notice.ts +29 -2
- package/lib/plan-entry.ts +7 -2
- package/lib/policy.ts +12 -2
- package/lib/qr.ts +64 -0
- package/lib/repo-key.ts +74 -0
- package/lib/report.ts +52 -33
- package/lib/requirements.ts +7 -9
- package/lib/session-label.ts +64 -0
- package/lib/session-roster.ts +130 -0
- package/lib/session-tool.ts +184 -0
- package/lib/tool-names.ts +25 -2
- package/lib/tui/README.md +16 -2
- package/lib/tui/dock-screen.ts +85 -17
- package/lib/tui/glyphs.ts +2 -0
- package/lib/tui/line-pane.ts +15 -4
- package/lib/tui/tool.ts +23 -4
- package/lib/web/README.md +5 -2
- package/lib/web/components.ts +6 -1
- package/lib/web/runtime.ts +7 -1
- package/lib/web/tokens.ts +25 -2
- package/package.json +27 -14
- package/skills/init/SKILL.md +80 -45
- package/skills/init/references/agents-md-quality.md +26 -2
- package/skills/init/references/interview-questions.md +36 -14
- package/skills/next/SKILL.md +77 -51
- package/skills/project-docs/SKILL.md +133 -0
- package/skills/project-docs/references/audit.md +131 -0
- package/skills/project-docs/references/changelog.md +105 -0
- package/skills/project-docs/references/discovery.md +127 -0
- package/skills/project-docs/references/readme.md +80 -0
- package/skills/project-docs/references/release.md +84 -0
- package/skills/project-docs/references/roadmap.md +93 -0
- package/skills/project-docs/scripts/state.ts +316 -0
- package/skills/refactor/SKILL.md +100 -125
- package/skills/refactor/references/handoff.md +35 -0
- package/skills/refactor/references/signals.md +54 -0
- package/skills/refactor/scripts/inventory.ts +587 -0
- package/extensions/file-browse/README.md +0 -467
- package/extensions/file-browse/server.ts +0 -134
- package/extensions/plan/README.md +0 -709
- package/extensions/plan/config.ts +0 -27
- package/extensions/wechat/outbound.ts +0 -100
- package/extensions/wechat/qrcode.ts +0 -46
- package/skills/changelog/SKILL.md +0 -148
- /package/extensions/file-browse/{diff.ts → text/diff.ts} +0 -0
- /package/extensions/file-browse/{fuzzy.ts → text/fuzzy.ts} +0 -0
- /package/extensions/file-browse/{palette.ts → view/palette.ts} +0 -0
- /package/extensions/rewind/{patch.ts → text/patch.ts} +0 -0
- /package/extensions/rewind/{paths.ts → text/paths.ts} +0 -0
- /package/extensions/rewind/{queue.ts → transport/queue.ts} +0 -0
- /package/extensions/rewind/{temp-index.ts → transport/temp-index.ts} +0 -0
- /package/extensions/wechat/{lock.ts → state/lock.ts} +0 -0
- /package/extensions/wechat/{channel.ts → text/channel.ts} +0 -0
|
@@ -1,354 +1,96 @@
|
|
|
1
1
|
# bytefly — the TUI header, footer, user-message marker, turn rule, extension screen, and notifications
|
|
2
2
|
|
|
3
|
-
`bytefly` owns the terminal chrome, configuration, and diagnostics surfaces
|
|
4
|
-
|
|
5
|
-
the
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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,
|
|
12
|
-
a job finishes, or the agent asks for input, and a package-update check that
|
|
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.
|
|
15
|
-
DeepSeek is priced from the provider's published yuan rates and peak tariff by
|
|
16
|
-
default; set `price.currency.code` to `USD` to price it from the provider's
|
|
17
|
-
published dollar table instead, under the same peak windows, with Pi's recorded
|
|
18
|
-
dollars covering a model the table does not list. Any other model can be priced
|
|
19
|
-
from your own yuan rates when Pi's
|
|
20
|
-
catalog does not match what a provider actually charges.
|
|
3
|
+
`bytefly` owns the terminal chrome, configuration, and diagnostics surfaces this
|
|
4
|
+
package adds: the startup header and footer, the user-message nameplate, the turn
|
|
5
|
+
rule, the shared notice and tool-block frames, the working line, the `/bytefly`
|
|
6
|
+
control center, OS notifications, and the package-update check. Every surface is
|
|
7
|
+
drawn from the package's `lib/tui/` design system, so a theme swap re-skins the
|
|
8
|
+
whole chrome. The footer prices a session from DeepSeek's published rates by
|
|
9
|
+
default, and from `bytefly.json` otherwise.
|
|
21
10
|
|
|
22
|
-
|
|
23
|
-
pi --extension ./extensions/bytefly # load just this extension
|
|
24
|
-
pi -e . # load the whole @gavin-hu/my-pi-agent package
|
|
25
|
-
pi install ./ # install the package
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Tool rendering
|
|
29
|
-
|
|
30
|
-
How the `run_doctor` call and its result look in the transcript — the call line as a headline and the body indented under it:
|
|
31
|
-
|
|
32
|
-
<img src="../../assets/tools/run_doctor.png" alt="The run_doctor tool's result: the call line and a one-line, indented doctor summary with a collapsed expand hint" width="100%">
|
|
33
|
-
|
|
34
|
-
## What it does
|
|
35
|
-
|
|
36
|
-
The extension owns ten surfaces: the startup header, the footer, the
|
|
37
|
-
user-message marker, the rule between completed turns, the notice block for
|
|
38
|
-
shared transcript notices, the tool-block frame, the live working line, the
|
|
39
|
-
three-section control center, notifications, and the update check.
|
|
40
|
-
|
|
41
|
-
**Header.** A nameplate: a two-tone half-block mark from the active theme's
|
|
42
|
-
`accent` / `warn` roles, the agent identity (`Pi`, bold, and its version), the
|
|
43
|
-
chrome identity (`enhanced by bytefly` and the package version), a signature
|
|
44
|
-
rule whose `accent` lead sits under the mark, and a grouped help block. The help
|
|
45
|
-
keys resolve live from Pi's keybindings, so a rebound key shows the user's
|
|
46
|
-
chord; the identity and help text are `meta` / `faint` so the mark keeps the
|
|
47
|
-
eye. It opens with a blank row, so the nameplate clears the top edge. It is
|
|
48
|
-
installed only in interactive (`tui`) sessions when Pi's
|
|
49
|
-
`quietStartup` is `true` — the Settings row **Bytefly startup TUI** — and
|
|
50
|
-
`false`, `"header"`, and unset leave Pi's built-in header in place; on terminals
|
|
51
|
-
that cannot render half blocks the mark falls back to a two-tone `Pi` wordmark.
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
█▀█ Pi v1.2.0
|
|
55
|
-
█▀ █ enhanced by bytefly v0.8.1
|
|
56
|
-
─────────────────────────────────────────────────
|
|
57
|
-
escape to interrupt · ctrl+c to clear · ctrl+d to exit (empty)
|
|
58
|
-
ctrl+o to expand tools · ctrl+t to expand thinking · ctrl+l to select model
|
|
59
|
-
/ commands · ! bash · !! bash (no context) · /bytefly extensions
|
|
60
|
-
```
|
|
61
|
-
|
|
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
|
|
65
|
-
all three help groups print, below 28 the middle group (the expand and model
|
|
66
|
-
chords) goes first, below 22 only the `/` commands row survives, and below 16 the
|
|
67
|
-
help block and the leading blank row go, leaving the nameplate and its rule. An
|
|
68
|
-
unknown height keeps the full header. The nameplate sits on the transcript
|
|
69
|
-
margin, which follows Pi's `outputPad` (the value the tool frame and the notice
|
|
70
|
-
use too), and the help hangs one body indent inside it. The mark, tokens,
|
|
71
|
-
identity, and grouped help are tuned in
|
|
72
|
-
[`header/config.ts`](./header/config.ts).
|
|
73
|
-
|
|
74
|
-
**Footer.** Two lines, each with a left and right zone:
|
|
75
|
-
|
|
76
|
-
- **Line 1 — identity:** `pwd` and the session name on the left; git state
|
|
77
|
-
(`⎇ branch · ⑂ worktree`) and the `◉` browse chip on the right.
|
|
78
|
-
- **Line 2 — resources:** the context gauge and usage meters on the left, the
|
|
79
|
-
child-run roll-up (`↳ 3 · ¥0.12`, present only once a subagent has finished),
|
|
80
|
-
the mode/alert slot (`≡ plan`) trailing after a `│` when present, and the model
|
|
81
|
-
and thinking level on the right. The gauge is anchored at column 0, so `%` is
|
|
82
|
-
always in the same place.
|
|
83
|
-
The roll-up is its own number, never folded into the session's cost: a subagent
|
|
84
|
-
runs in its own process, and the footer prices those runs with the same rate
|
|
85
|
-
table and currency as the session so a currency change moves both. It covers
|
|
86
|
-
the last 500 child runs of the current process, and starts from zero after
|
|
87
|
-
`/resume` (the events are not session entries).
|
|
88
|
-
|
|
89
|
-
```
|
|
90
|
-
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
91
|
-
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↳ 2 · ¥0.06 · ↑42k ↓8.0k · R96k CH 87% │ ≡ plan opus-4.5 · high
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
(The examples show the default `¥` symbol. A model that neither `rates` nor the
|
|
95
|
-
built-in table covers contributes nothing in `CNY` mode, so the bar shows no
|
|
96
|
-
figure rather than a guessed one; `USD` mode adds Pi's recorded dollars for that
|
|
97
|
-
record instead — see the currency note under [Configuration](#configuration).)
|
|
98
|
-
|
|
99
|
-
With no plan mode there is no mode slot, so the `│` is omitted:
|
|
100
|
-
|
|
101
|
-
```
|
|
102
|
-
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
103
|
-
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
As the terminal narrows, segments shrink and drop by priority rather than
|
|
107
|
-
clipping. The branch keeps its name and is dropped when the name no longer
|
|
108
|
-
fits, rather than collapsing to a bare glyph:
|
|
109
|
-
|
|
110
|
-
```
|
|
111
|
-
~/repo/project ⎇ main · ⑂ smoke
|
|
112
|
-
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31 │ ≡ plan opus-4.5 · high
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
project ⎇ main
|
|
117
|
-
62% ≡ opus-4.5
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
With a named session, the name follows the path and truncates before it drops:
|
|
121
|
-
|
|
122
|
-
```
|
|
123
|
-
~/repo/project · feature-refac… ⎇ main
|
|
124
|
-
▰▰▰▰▰▰▱▱▱▱ 62% │ ≡ plan opus-4.5
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Zero-value meters are omitted, so a fresh session shows only `?/window` instead
|
|
128
|
-
of a row of `¥0.00 · ↑0 ↓0 · R0 W0`. Unknown context usage shows a muted `?`
|
|
129
|
-
with no gauge (known `0%` still draws the empty gauge), so unknown and zero stay
|
|
130
|
-
distinct. Cost keeps the configured precision — the segment drops rather than
|
|
131
|
-
rounding to a misleading `¥0.3` — and a positive amount below one minor unit
|
|
132
|
-
shows as `¥<0.01` rather than `¥0.00`.
|
|
133
|
-
|
|
134
|
-
DeepSeek needs no config file at all: the bar prices it from the published yuan
|
|
135
|
-
rates and peak tariff built into [`footer/price/config.ts`](./footer/price/config.ts).
|
|
136
|
-
Those tables record the day they were last checked against the published tariff,
|
|
137
|
-
and `doctor` reports how old that is, so a re-pricing shows up as a warning instead
|
|
138
|
-
of a quietly wrong total. A `bytefly.json` can switch to the published dollar table,
|
|
139
|
-
add models of your own, or replace a built-in entry:
|
|
140
|
-
|
|
141
|
-
```
|
|
142
|
-
~/repo/project ⎇ main
|
|
143
|
-
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥2.50 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Session budget.** `price.budget` puts a threshold under that total, in the same
|
|
147
|
-
currency: when the session's cost reaches it, one `bytefly · Session budget
|
|
148
|
-
reached` notice names what was spent against the budget, and one OS notification
|
|
149
|
-
follows when notify is enabled. It is an alert, not a limit — no turn is blocked or
|
|
150
|
-
aborted — and it fires once per session, on the turn where the crossing becomes
|
|
151
|
-
final (the run settling), because a warning per turn after that is noise. `0`, the
|
|
152
|
-
default, turns it off. The check reads the total the footer already priced, and
|
|
153
|
-
the footer exists only in `tui` sessions, so a print or JSON run has no budget
|
|
154
|
-
alert; the footer's own numbers are visible in every interactive session.
|
|
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
|
-
|
|
165
|
-
**User message.** Every user message opens with a two-row `You` nameplate —
|
|
166
|
-
the label over a rule that spans the width — above the message:
|
|
167
|
-
|
|
168
|
-
```
|
|
169
|
-
You
|
|
170
|
-
────────────────────────────────────
|
|
171
|
-
|
|
172
|
-
the message the user typed
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
It is always on in interactive sessions and has no config file. Pi renders a
|
|
176
|
-
user message as Markdown and owns its colors, so bytefly's only lever is a
|
|
177
|
-
`registerMarkdownTransformer`: the nameplate is a single level-2 heading whose
|
|
178
|
-
text is padded so the rule wraps onto the second row, and both rows carry the
|
|
179
|
-
accent because the themes point `mdHeading` at it. The block carries no fill —
|
|
180
|
-
the shipped themes set `userMessageBg` to the terminal default, so it reads like
|
|
181
|
-
the tool blocks. The nameplate is separated from the message by a blank line, so
|
|
182
|
-
the message's own Markdown (a fence, a list, a second paragraph) parses exactly
|
|
183
|
-
as it would without it, and a soft wrap of one long line stays at the margin
|
|
184
|
-
because the renderer wraps it, not bytefly. The label and the rule are tuned
|
|
185
|
-
in [`message/config.ts`](./message/config.ts).
|
|
186
|
-
|
|
187
|
-
**Working line.** Pi's working row shows a static `Working`, so a long run
|
|
188
|
-
reads the same as a short one. While the row is up, bytefly advances its
|
|
189
|
-
message once a second and hands it back to Pi when the row comes down. Before
|
|
190
|
-
the first tool starts it is a count:
|
|
191
|
-
|
|
192
|
-
```
|
|
193
|
-
Working… 12s
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
Once a top-level tool starts, the row becomes a live run line: the tool, how
|
|
197
|
-
many top-level tools this run has started, and the elapsed time.
|
|
11
|
+
## Capabilities
|
|
198
12
|
|
|
199
|
-
|
|
200
|
-
edit · 3 tools · 12s
|
|
201
|
-
```
|
|
13
|
+
Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
|
|
202
14
|
|
|
203
|
-
|
|
204
|
-
inner call) neither counts nor takes over the line, so the number matches the
|
|
205
|
-
tool blocks in the transcript. The line keeps the last tool name while the
|
|
206
|
-
model streams after it, and a tool event repaints the row immediately instead
|
|
207
|
-
of waiting for the next tick. The line covers the whole run, tool calls
|
|
208
|
-
included. It is tied to the row's visibility: it starts on `turn_start`, stops
|
|
209
|
-
on `agent_end`, and is reset on `session_shutdown`; turns inside one run do not
|
|
210
|
-
restart it, and a retry starts a new run. The words and the interval are tuned
|
|
211
|
-
in [`working/config.ts`](./working/config.ts).
|
|
15
|
+
### Chrome
|
|
212
16
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
17
|
+
| Capability | How | What you get | Status |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| Startup header | `quietStartup` | One two-tone nameplate with the agent and chrome versions and the live help keys, in place of Pi's startup header and resource listing. | Shipped |
|
|
20
|
+
| Two-line footer | every `tui` session | Location, branch, context, spend, and model on two lines that shed parts rather than clip. | Shipped |
|
|
21
|
+
| Extension status chips | `footerData.getExtensionStatuses()` | Worktree, browse, plan, and alert statuses appear in the footer, using each extension's own colour. | Shipped |
|
|
22
|
+
| Priced session total | the `price` section of `bytefly.json` | The session's spend in yuan or dollars, with DeepSeek priced out of the box. | Shipped |
|
|
23
|
+
| Delegated-run cost roll-up | the `↳` footer segment | A finished subagent's cost appears beside the session total, without merging the two ledgers. | Shipped |
|
|
24
|
+
| User-message nameplate | every `tui` session | Each user message opens with a two-row `You` label and rule. | Shipped |
|
|
25
|
+
| Turn receipt | the `bytefly-separator` entry | One rule per completed turn, recording its number, duration, tool count, and outcome. | Shipped |
|
|
26
|
+
| Shared notices | the `my-pi-agent/notice` type | Any extension's notice renders at the transcript margin with a severity-coloured rail. | Shipped |
|
|
27
|
+
| Compaction canvas | the shipped `themes/` palettes | Pi's `/compact` block keeps its content and loses its fill, so it sits on the canvas. | Shipped |
|
|
28
|
+
| Tool-block frame | `registerToolRenderer` | Every tool block leads with its own call line and hangs its result from the transcript rail. | Shipped |
|
|
29
|
+
| Working line | `ctx.ui.setWorkingMessage` | The working row counts seconds, then names the running tool and how many tools the run has started. | Shipped |
|
|
30
|
+
|
|
31
|
+
### Control center
|
|
32
|
+
|
|
33
|
+
| Capability | How | What you get | Status |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| Extension list | `/bytefly` | Every resolved extension with an enable checkbox, one health verdict, and its findings. | Shipped |
|
|
36
|
+
| Settings list | `/bytefly settings` | The curated preferences with each value beside its label, editable in place. | Shipped |
|
|
37
|
+
| Theme selection | the `Theme` row in `/bytefly settings` | `system` and the package's `bytefly-dark` and `bytefly-light` palettes are one selection; a reload applies it. | Shipped |
|
|
38
|
+
| Skill list | `/bytefly skills` | Every resolved skill with the same checkbox and the description its `SKILL.md` declares. | Shipped |
|
|
39
|
+
| Scoped writes | `Tab`, `Space`, `x` | A toggle lands in the personal or project `settings.json`, and `x` clears a project override. | Shipped |
|
|
40
|
+
| Reload after changes | `/bytefly` after a pending write | The screen offers the reload that applies extension, skill, or setting changes instead of leaving the session to be restarted by hand. | Shipped |
|
|
41
|
+
| Health report | `run_doctor`, `/bytefly doctor` | Prerequisites, parse errors, and aged rate tables as text and typed data. | Shipped |
|
|
217
42
|
|
|
218
|
-
|
|
219
|
-
shared `my-pi-agent/notice` type; bytefly draws it at the transcript's margin —
|
|
220
|
-
a `source · title` headline at the margin, then rail-led rows, each with its own
|
|
221
|
-
severity glyph:
|
|
43
|
+
### Upkeep
|
|
222
44
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
45
|
+
| Capability | How | What you get | Status |
|
|
46
|
+
|---|---|---|---|
|
|
47
|
+
| Currency and peak tariff | `price.currency.code`, `price.peak` | `CNY` and `USD` are separate pricing methods with published rates; DeepSeek's peak windows apply per token record. | Shipped |
|
|
48
|
+
| Session budget alert | `price.budget` | One notice, and one OS notification, when the session total reaches the threshold. | Shipped |
|
|
49
|
+
| Unpriced-record notice | `price.currency.code` | A `CNY` session names the records it could not price, and the two ways to fix it. | Shipped |
|
|
50
|
+
| Desktop notifications | `notify.enabled`, `notify.turnFinished`, `notify.needsInput`, `notify.jobFinished`, `notify.matchFound` | An OS notification when a run settles, the agent needs you, a job finishes, or a watcher matches. | Shipped |
|
|
51
|
+
| Proactive health check | `doctor.proactive` | At session start, when the startup header is on, a hard requirement is probed once and reported before the first turn. | Shipped |
|
|
52
|
+
| Update check | `/bytefly update` | One notice per session lists every package behind, and the header marks a new version. | Shipped |
|
|
53
|
+
| Update action | `/bytefly upgrade` | Pi's own package manager installs the configured packages behind a confirmation, clearing the marker and naming the reload the new version needs. | Unreleased |
|
|
54
|
+
| Pi release notice | `automatic: Pi's release notice` | Pi's own newer version gets the same themed notice and header marker, without a second check. | Shipped |
|
|
55
|
+
|
|
56
|
+
## Quickstart
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pi --extension ./extensions/bytefly # load just this extension
|
|
60
|
+
pi -e . # load the whole @gavin-hu/my-pi-agent package
|
|
61
|
+
pi install ./ # install the package for a user
|
|
227
62
|
```
|
|
228
63
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
notice stays body text. A row's label stays body text too: its severity is the
|
|
233
|
-
glyph it hangs on, so one failing row never tints the rest of the list.
|
|
234
|
-
|
|
235
|
-
`job` and `watch` post one when a background job finishes or a watched line
|
|
236
|
-
matches, so the report the model reads is visible too. `doctor` posts one when a
|
|
237
|
-
hard requirement is missing at session start, with a row per finding and the
|
|
238
|
-
command that fixes it:
|
|
239
|
-
|
|
240
|
-
```
|
|
241
|
-
doctor · 1 missing prerequisite
|
|
242
|
-
╎ ✕ worktree (git) · install git and make sure it is on PATH
|
|
64
|
+
```text
|
|
65
|
+
/bytefly # the control center, on Extensions
|
|
66
|
+
/bytefly doctor # the report run_doctor returns
|
|
243
67
|
```
|
|
244
68
|
|
|
245
|
-
|
|
246
|
-
[`lib/notice.ts`](../../lib/notice.ts), and the severity glyphs and item cap
|
|
247
|
-
are tuned in [`notice/config.ts`](./notice/config.ts). Every field is sanitized
|
|
248
|
-
and clipped at the boundary, and a message without `details` keeps Pi's default
|
|
249
|
-
custom-message box.
|
|
250
|
-
|
|
251
|
-
**Compaction.** `/compact` is Pi's own surface: its summary block is a built-in
|
|
252
|
-
message component, so bytefly cannot replace, hide, or shorten it. The shipped
|
|
253
|
-
themes only remove its fill — `customMessageBg` is the terminal default — and
|
|
254
|
-
paint the `[compaction]` label in the accent, so the block sits on the canvas
|
|
255
|
-
like the rest of the transcript. Pi's branch summaries and skill invocations
|
|
256
|
-
share the same tokens.
|
|
257
|
-
|
|
258
|
-
<img src="../../assets/compaction.png" alt="The /compact summary block: a [compaction] label, the compacted token count, and the summary Markdown on the terminal canvas, with no background band" width="100%">
|
|
259
|
-
|
|
260
|
-
**Tool blocks.** Every tool block leads with the tool's own call line as the
|
|
261
|
-
headline — the tool name in the theme's tool-title colour — and its result body
|
|
262
|
-
sits two columns in directly beneath it, led by the transcript rail, instead of
|
|
263
|
-
Pi's filled status background:
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
read src/app.ts
|
|
267
|
-
╎ const answer = 42;
|
|
268
|
-
```
|
|
69
|
+
## Tool
|
|
269
70
|
|
|
270
|
-
The
|
|
271
|
-
call body — the edit diff, the written file content — so that body is railed
|
|
272
|
-
like any other result. There is no status band: the diff's own red/green line
|
|
273
|
-
colours, with the changed words in reverse video, and the `edit` / `write`
|
|
274
|
-
headline are what mark a file change.
|
|
71
|
+
<img src="../../assets/tools/run_doctor.png" alt="The run_doctor tool's result: the call line and a one-line, indented doctor summary with a collapsed expand hint" width="100%">
|
|
275
72
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
tool's own
|
|
283
|
-
`renderCall`/`renderResult` are passed through, so syntax highlighting, diffs,
|
|
284
|
-
previews, and truncation notices are unchanged — only the frame is bytefly's.
|
|
285
|
-
The body carries the transcript rail, painted by status (a running result takes
|
|
286
|
-
the accent, a failure red, a finished one neutral) and drawn with the glyph from
|
|
287
|
-
the `chrome.rail` setting. A result frame is always railed; a call frame is railed
|
|
288
|
-
only for `edit` and `write`, whose call body carries the result — every other
|
|
289
|
-
call's headline and continuation lines stay plain-indented. Package renderers
|
|
290
|
-
clip a call to one physical line (middle clip for a path or URL), so it cannot
|
|
291
|
-
leak into the body column; Pi's own renderers still wrap, and the frame keeps a
|
|
292
|
-
wrapped continuation unrailed and loses the accent there too, with the rail
|
|
293
|
-
beginning at the result underneath. A rejected call renders as one sanitized
|
|
294
|
-
`error` line in the error role; a running tool shows a live elapsed label, and a
|
|
295
|
-
finished long call appends its duration. A tool with
|
|
296
|
-
no renderer of its own is framed around a generic call/result fallback, whose
|
|
297
|
-
call line reads like a built-in — the leading string argument bare, the rest as
|
|
298
|
-
trailing options (`open_path src/app.ts`) — rather than dumping raw `key=value`
|
|
299
|
-
pairs. A tool that draws its own shell (`edit`) is framed too:
|
|
300
|
-
`renderShell: "self"` only tells Pi not to draw its box around the renderer, so
|
|
301
|
-
its diff would otherwise sit at the wrong indent; the frame drops the blank
|
|
302
|
-
edges its own `Box` pads itself with, and hands it a theme whose `bg` is inert so
|
|
303
|
-
it never paints a band the rest of the transcript does not have.
|
|
73
|
+
`run_doctor` — `exposure: "direct"` (the default), `executionMode: "sequential"`,
|
|
74
|
+
read-only, closed-world. It reports whether each extension has what it needs at
|
|
75
|
+
runtime — binaries on `PATH`, optional packages and browsers, login and state
|
|
76
|
+
files, and config files that fail to parse — and it probes and changes nothing.
|
|
77
|
+
Its `readOnlyHint` is what the shared default-deny policy in `lib/policy.ts`
|
|
78
|
+
reads to allow it in plan mode.
|
|
304
79
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
`
|
|
309
|
-
shipped themes point `toolTitle` at the accent and `label` at the body colour, so
|
|
310
|
-
the name is the call line's one accent and the subject follows as body text; a
|
|
311
|
-
theme that maps `toolTitle` elsewhere is respected rather than overridden.
|
|
80
|
+
| Parameter | Type | Meaning |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| `extension` | string, optional | Report a single extension instead of every extension. |
|
|
83
|
+
| `refresh` | boolean, optional | Ignore the findings cached earlier in this session and probe again. |
|
|
312
84
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
the matching `settings.json`. `←`/`→` switch to Settings, which lists the
|
|
318
|
-
preferences this package and Pi expose: bytefly startup TUI, desktop notifications,
|
|
319
|
-
the transcript rail glyph, output padding, and the hardware cursor. The focused
|
|
320
|
-
extension's findings, or the focused setting's source and target file, sit
|
|
321
|
-
underneath, and `run_doctor` returns the same report as text and typed data.
|
|
322
|
-
Only a missing
|
|
323
|
-
*hard* requirement posts a notice at session start; everything else waits in the
|
|
324
|
-
report.
|
|
325
|
-
See [The control center](#the-control-center).
|
|
326
|
-
|
|
327
|
-
**Notify.** Off by default, one `notify` section in `bytefly.json` turns on OS
|
|
328
|
-
notifications for unattended runs: when a full agent run settles, when a
|
|
329
|
-
background job finishes, when the agent opens a prompt asking for input, and when
|
|
330
|
-
a `watch` wake match fires while the agent is idle. The
|
|
331
|
-
method follows the terminal (OSC 777, OSC 99, a Windows toast) or falls back to
|
|
332
|
-
the platform notifier (`osascript`, `notify-send`); see
|
|
333
|
-
[Notifications](#notifications).
|
|
334
|
-
|
|
335
|
-
**Update check.** In the background at an interactive session's start, Pi's
|
|
336
|
-
package manager reports which configured packages are behind. bytefly suppresses
|
|
337
|
-
Pi's own startup block, caches the snapshot in `<agentDir>/bytefly/update.json`
|
|
338
|
-
with the time it was read, and posts one transcript notice listing every package
|
|
339
|
-
plus `pi update --extensions`. This package's new version alone puts `↑0.12.0`
|
|
340
|
-
after the header's chrome version and adds its release URL to the notice. A
|
|
341
|
-
session inside the 24-hour window reuses the cache without a package-manager
|
|
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).
|
|
85
|
+
Result (`details` / `structuredContent`): `{ headline, missing, degraded, extensions }`,
|
|
86
|
+
one finding per check with its `check`, `severity`, `detail`, and optional `hint`.
|
|
87
|
+
The same report is what `/bytefly doctor` prints, and what
|
|
88
|
+
[the control center](#the-control-center) draws.
|
|
349
89
|
|
|
350
90
|
## Commands
|
|
351
91
|
|
|
92
|
+
One command runs the screen, prints the report, and re-checks updates:
|
|
93
|
+
|
|
352
94
|
| Command | What it does |
|
|
353
95
|
|---|---|
|
|
354
96
|
| `/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. |
|
|
@@ -356,9 +98,11 @@ next session tries again; see [Update check](#update-check).
|
|
|
356
98
|
| `/bytefly skills` | Open the control center on Skills. Outside `tui` it prints the grouped skills listing with one row per skill. |
|
|
357
99
|
| `/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. |
|
|
358
100
|
| `/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. |
|
|
101
|
+
| `/bytefly upgrade` | Install what the check found, behind a confirmation: Pi's own package manager updates every configured package, the marker is re-read, and one line reports the result and the reload it needs. `PI_OFFLINE` and a pinned npm version skip the work. It resolves no packages and mounts no screen. |
|
|
359
102
|
|
|
360
103
|
Tab completes the subcommands, extension names after `doctor`, and `refresh`;
|
|
361
|
-
`/bytefly settings`, `/bytefly skills`,
|
|
104
|
+
`/bytefly settings`, `/bytefly skills`, `/bytefly update`, and `/bytefly upgrade`
|
|
105
|
+
take no name.
|
|
362
106
|
|
|
363
107
|
## Behaviour by mode
|
|
364
108
|
|
|
@@ -387,20 +131,20 @@ print/JSON/RPC run gets an OS-level notification or none.
|
|
|
387
131
|
Two things are JSON: the transcript rail's glyph (`chrome.rail`, default `╎`,
|
|
388
132
|
read at `session_start`/`session_tree`) and this extension's three config
|
|
389
133
|
sections — `price`, `notify`, and `doctor`. Everything else about the look is
|
|
390
|
-
tuned in code: the header in [`header/config.ts`](
|
|
134
|
+
tuned in code: the header in [`header/config.ts`](../../extensions/bytefly/header/config.ts) (mark and
|
|
391
135
|
identity tokens, tagline, grouped help), the footer in
|
|
392
|
-
[`footer/config.ts`](
|
|
136
|
+
[`footer/config.ts`](../../extensions/bytefly/footer/config.ts) (thresholds, gauge glyphs and widths,
|
|
393
137
|
separators, icons, status keys), and the turn separator in
|
|
394
|
-
[`separator/config.ts`](
|
|
138
|
+
[`separator/config.ts`](../../extensions/bytefly/separator/config.ts) (glyph, label prefix, padding,
|
|
395
139
|
minimum duration, outcome wording, colors).
|
|
396
140
|
|
|
397
141
|
Every key of every section is listed with its type, default, and bounds in
|
|
398
|
-
[`docs/configuration.md`](
|
|
142
|
+
[`docs/configuration.md`](../configuration.md); this section
|
|
399
143
|
covers what that table cannot — when each section is read, and what the cost
|
|
400
144
|
does when no rate matches.
|
|
401
145
|
|
|
402
146
|
`bytefly.json` is one shared document with a top-level section per extension (see
|
|
403
|
-
[Configuration](
|
|
147
|
+
[Configuration](../configuration.md)). It is read from the global
|
|
404
148
|
document, then `<cwd>/.pi/bytefly.json`, project winning. The old per-extension
|
|
405
149
|
files (`document.json`, `jobs.json`, …) are no longer read; `bun run config:migrate`
|
|
406
150
|
moves them into the shared document.
|
|
@@ -477,13 +221,140 @@ the model reads the same sentence.
|
|
|
477
221
|
- The extension screen registers no model-facing tool; toggling writes only
|
|
478
222
|
through Pi's `settings.json`, and `run_doctor` is read-only.
|
|
479
223
|
|
|
224
|
+
## Startup header
|
|
225
|
+
|
|
226
|
+
A nameplate: a two-tone half-block mark from the active theme's `accent` /
|
|
227
|
+
`warn` roles, the agent identity (`Pi`, bold, and its version), the chrome
|
|
228
|
+
identity (`enhanced by bytefly` and the package version), a signature rule whose
|
|
229
|
+
`accent` lead sits under the mark, and a grouped help block. The help keys
|
|
230
|
+
resolve live from Pi's keybindings, so a rebound key shows the user's chord; the
|
|
231
|
+
identity and help text are `meta` / `faint` so the mark keeps the eye. It opens
|
|
232
|
+
with a blank row, so the nameplate clears the top edge. It is installed only in
|
|
233
|
+
interactive (`tui`) sessions when Pi's `quietStartup` is `true` — the Settings
|
|
234
|
+
row **Bytefly startup TUI** — and `false`, `"header"`, and unset leave Pi's
|
|
235
|
+
built-in header in place; on terminals that cannot render half blocks the mark
|
|
236
|
+
falls back to a two-tone `Pi` wordmark.
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
█▀█ Pi v1.2.0
|
|
240
|
+
█▀ █ enhanced by bytefly v0.8.1
|
|
241
|
+
─────────────────────────────────────────────────
|
|
242
|
+
escape to interrupt · ctrl+c to clear · ctrl+d to exit (empty)
|
|
243
|
+
ctrl+o to expand tools · ctrl+t to expand thinking · ctrl+l to select model
|
|
244
|
+
/ commands · ! bash · !! bash (no context) · /bytefly extensions
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
As the terminal narrows, the identity sheds the chrome marker, then the chrome
|
|
248
|
+
version, then the chrome line, then Pi's marker with the agent name, and the help
|
|
249
|
+
rows drop whole keys, so nothing wraps or clips mid-word. Height sheds the same way: at 28 rows
|
|
250
|
+
all three help groups print, below 28 the middle group (the expand and model
|
|
251
|
+
chords) goes first, below 22 only the `/` commands row survives, and below 16 the
|
|
252
|
+
help block and the leading blank row go, leaving the nameplate and its rule. An
|
|
253
|
+
unknown height keeps the full header. The nameplate sits on the transcript
|
|
254
|
+
margin, which follows Pi's `outputPad` (the value the tool frame and the notice
|
|
255
|
+
use too), and the help hangs one body indent inside it. The mark, tokens,
|
|
256
|
+
identity, and grouped help are tuned in
|
|
257
|
+
[`header/config.ts`](../../extensions/bytefly/header/config.ts).
|
|
258
|
+
|
|
259
|
+
## Content and colors
|
|
260
|
+
|
|
261
|
+
Two lines, each with a left and right zone:
|
|
262
|
+
|
|
263
|
+
- **Line 1 — identity:** `pwd` and the session name on the left; git state
|
|
264
|
+
(`⎇ branch · ⑂ worktree`) and the `◉` browse chip on the right.
|
|
265
|
+
- **Line 2 — resources:** the context gauge and usage meters on the left, the
|
|
266
|
+
child-run roll-up (`↳ 3 · ¥0.12`, present only once a subagent has finished),
|
|
267
|
+
the mode/alert slot (`≡ plan`) trailing after a `│` when present, and the model
|
|
268
|
+
and thinking level on the right. The gauge is anchored at column 0, so `%` is
|
|
269
|
+
always in the same place.
|
|
270
|
+
The roll-up is its own number, never folded into the session's cost: a subagent
|
|
271
|
+
runs in its own process, and the footer prices those runs with the same rate
|
|
272
|
+
table and currency as the session so a currency change moves both. It covers
|
|
273
|
+
the last 500 child runs of the current process, and starts from zero after
|
|
274
|
+
`/resume` (the events are not session entries).
|
|
275
|
+
|
|
276
|
+
```
|
|
277
|
+
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
278
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↳ 2 · ¥0.06 · ↑42k ↓8.0k · R96k CH 87% │ ≡ plan opus-4.5 · high
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
(The examples show the default `¥` symbol. A model that neither `rates` nor the
|
|
282
|
+
built-in table covers contributes nothing in `CNY` mode, so the bar shows no
|
|
283
|
+
figure rather than a guessed one; `USD` mode adds Pi's recorded dollars for that
|
|
284
|
+
record instead — see [Cost calculation](#cost-calculation).)
|
|
285
|
+
|
|
286
|
+
With no plan mode there is no mode slot, so the `│` is omitted:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
290
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
As the terminal narrows, segments shrink and drop by priority rather than
|
|
294
|
+
clipping. The branch keeps its name and is dropped when the name no longer
|
|
295
|
+
fits, rather than collapsing to a bare glyph:
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
~/repo/project ⎇ main · ⑂ smoke
|
|
299
|
+
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31 │ ≡ plan opus-4.5 · high
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
project ⎇ main
|
|
304
|
+
62% ≡ opus-4.5
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
With a named session, the name follows the path and truncates before it drops:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
~/repo/project · feature-refac… ⎇ main
|
|
311
|
+
▰▰▰▰▰▰▱▱▱▱ 62% │ ≡ plan opus-4.5
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
Zero-value meters are omitted, so a fresh session shows only `?/window` instead
|
|
315
|
+
of a row of `¥0.00 · ↑0 ↓0 · R0 W0`. Unknown context usage shows a muted `?`
|
|
316
|
+
with no gauge (known `0%` still draws the empty gauge), so unknown and zero stay
|
|
317
|
+
distinct. Cost keeps the configured precision — the segment drops rather than
|
|
318
|
+
rounding to a misleading `¥0.3` — and a positive amount below one minor unit
|
|
319
|
+
shows as `¥<0.01` rather than `¥0.00`.
|
|
320
|
+
|
|
321
|
+
Each segment reads a theme role and carries its own drop order:
|
|
322
|
+
|
|
323
|
+
| Segment | Line / zone | Color | Drops |
|
|
324
|
+
|---|---|---|---|
|
|
325
|
+
| pwd | 1 left | dim | last |
|
|
326
|
+
| session | 1 left | muted, bracketed | after worktree |
|
|
327
|
+
| browse | 1 right | success glyph + accent port | first |
|
|
328
|
+
| branch | 1 right | muted (warning when detached) | last |
|
|
329
|
+
| worktree | 1 right | success | first |
|
|
330
|
+
| context gauge + `%` | 2 left | muted ≤70 · warning 71–90 · error >90 | never |
|
|
331
|
+
| `/window` | 2 left | dim | before cost |
|
|
332
|
+
| cost | 2 left | muted | after tokens |
|
|
333
|
+
| tokens `↑in ↓out` | 2 left | dim | after cache |
|
|
334
|
+
| cache `R… CH …%` | 2 left | dim | first |
|
|
335
|
+
| statuses | 2 left | as emitted by each extension | before the model clips |
|
|
336
|
+
| model | 2 right | accent | never |
|
|
337
|
+
| thinking level | 2 right | thinking token | before cost |
|
|
338
|
+
|
|
339
|
+
The worktree status is read from the `worktree` status key, so the
|
|
340
|
+
[worktree](./worktree.md) extension and the bar agree. The browse chip is read
|
|
341
|
+
from the `browse` status key published by [file-browse](./file-browse.md) while
|
|
342
|
+
its server runs, and shows the two-tone `◉ <port>` (green glyph, accent port).
|
|
343
|
+
The trailing slot shows plan-style alerts when present and is omitted otherwise;
|
|
344
|
+
a plan chip's trailing plan file name is dropped, so the slot reads `≡ plan`
|
|
345
|
+
even though the built-in footer keeps the name. An alert (a failed job) sorts to
|
|
346
|
+
the front of the slot. The slot trails the meters after a `│`, so the context
|
|
347
|
+
gauge always starts the line. It keeps each extension's own colour when it
|
|
348
|
+
compacts, and it is droppable: a tight bar drops the slot rather than truncating
|
|
349
|
+
the model, which sits at the end of the line.
|
|
350
|
+
|
|
480
351
|
## Cost calculation
|
|
481
352
|
|
|
482
353
|
Pi prices every model call from its bundled catalog in USD, and the provider API
|
|
483
354
|
never returns a price. The footer can total that catalog directly, or replace
|
|
484
355
|
it with its own rates for the models they match:
|
|
485
356
|
|
|
486
|
-
- **Which built-in rates.** [`footer/price/config.ts`](
|
|
357
|
+
- **Which built-in rates.** [`footer/price/config.ts`](../../extensions/bytefly/footer/price/config.ts) ships DeepSeek's published
|
|
487
358
|
yuan prices for `CNY` and its published dollar prices for `USD`, per model, with
|
|
488
359
|
the peak schedule that doubles the price during peak hours
|
|
489
360
|
([DeepSeek's pricing page](https://api-docs.deepseek.com/quick_start/pricing)).
|
|
@@ -514,41 +385,66 @@ it with its own rates for the models they match:
|
|
|
514
385
|
leaves out; `USD` adds Pi's recorded dollar amount for that record, because
|
|
515
386
|
that number is already dollars and already per model.
|
|
516
387
|
|
|
388
|
+
DeepSeek needs no config file at all: the bar prices it from the published yuan
|
|
389
|
+
rates and peak tariff built into [`footer/price/config.ts`](../../extensions/bytefly/footer/price/config.ts).
|
|
390
|
+
Those tables record the day they were last checked against the published tariff,
|
|
391
|
+
and `doctor` reports how old that is, so a re-pricing shows up as a warning instead
|
|
392
|
+
of a quietly wrong total. A `bytefly.json` can switch to the published dollar table,
|
|
393
|
+
add models of your own, or replace a built-in entry:
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
~/repo/project ⎇ main
|
|
397
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥2.50 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
`price.budget` puts a threshold under that total, in the same currency: when the
|
|
401
|
+
session's cost reaches it, one `bytefly · Session budget reached` notice names
|
|
402
|
+
what was spent against the budget, and one OS notification follows when notify
|
|
403
|
+
is enabled. It is an alert, not a limit — no turn is blocked or aborted — and it
|
|
404
|
+
fires once per session, on the turn where the crossing becomes final (the run
|
|
405
|
+
settling), because a warning per turn after that is noise. `0`, the default,
|
|
406
|
+
turns it off. The check reads the total the footer already priced, and the
|
|
407
|
+
footer exists only in `tui` sessions, so a print or JSON run has no budget
|
|
408
|
+
alert; the footer's own numbers are visible in every interactive session.
|
|
409
|
+
|
|
410
|
+
`CNY` has no fallback, so a record for a model with no `price.rates` entry
|
|
411
|
+
contributes nothing to the total — with nothing on screen saying so. The footer
|
|
412
|
+
counts those records on the pass it already prices, and one
|
|
413
|
+
`bytefly · Records with no CNY rate` notice names the count and the two fixes:
|
|
414
|
+
switch `price.currency.code` to `USD` (Pi's catalog is per model, tiers included)
|
|
415
|
+
or add yuan `price.rates` entries. It fires once per session, on the run that
|
|
416
|
+
settles, like the budget alert. `USD` never counts one: Pi's recorded amount
|
|
417
|
+
covers every model.
|
|
418
|
+
|
|
517
419
|
For example, DeepSeek flash at `¥2` in and `¥8` out per million, with the
|
|
518
420
|
published peak windows and `offPeakMultiplier: 0.5`, prices a 1M-in + 1M-out
|
|
519
421
|
turn at `¥10.00` at peak and `¥5.00` off-peak. That example is worked end to end
|
|
520
|
-
in [`footer/footer.test.ts`](
|
|
422
|
+
in [`footer/footer.test.ts`](../../extensions/bytefly/footer/footer.test.ts), which also prices the built-in
|
|
521
423
|
table with no config file at all.
|
|
522
424
|
|
|
523
|
-
##
|
|
425
|
+
## The user-message nameplate
|
|
524
426
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
| pwd | 1 left | dim | last |
|
|
528
|
-
| session | 1 left | muted, bracketed | after worktree |
|
|
529
|
-
| browse | 1 right | success glyph + accent port | first |
|
|
530
|
-
| branch | 1 right | muted (warning when detached) | last |
|
|
531
|
-
| worktree | 1 right | success | first |
|
|
532
|
-
| context gauge + `%` | 2 left | muted ≤70 · warning 71–90 · error >90 | never |
|
|
533
|
-
| `/window` | 2 left | dim | before cost |
|
|
534
|
-
| cost | 2 left | muted | after tokens |
|
|
535
|
-
| tokens `↑in ↓out` | 2 left | dim | after cache |
|
|
536
|
-
| cache `R… CH …%` | 2 left | dim | first |
|
|
537
|
-
| statuses | 2 left | as emitted by each extension | before the model clips |
|
|
538
|
-
| model | 2 right | accent | never |
|
|
539
|
-
| thinking level | 2 right | thinking token | before cost |
|
|
427
|
+
Every user message opens with a two-row `You` nameplate — the label over a rule
|
|
428
|
+
that spans the width — above the message:
|
|
540
429
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
the
|
|
430
|
+
```
|
|
431
|
+
You
|
|
432
|
+
────────────────────────────────────
|
|
433
|
+
|
|
434
|
+
the message the user typed
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
It is always on in interactive sessions and has no config file. Pi renders a
|
|
438
|
+
user message as Markdown and owns its colors, so bytefly's only lever is a
|
|
439
|
+
`registerMarkdownTransformer`: the nameplate is a single level-2 heading whose
|
|
440
|
+
text is padded so the rule wraps onto the second row, and both rows carry the
|
|
441
|
+
accent because the themes point `mdHeading` at it. The block carries no fill —
|
|
442
|
+
the shipped themes set `userMessageBg` to the terminal default, so it reads like
|
|
443
|
+
the tool blocks. The nameplate is separated from the message by a blank line, so
|
|
444
|
+
the message's own Markdown (a fence, a list, a second paragraph) parses exactly
|
|
445
|
+
as it would without it, and a soft wrap of one long line stays at the margin
|
|
446
|
+
because the renderer wraps it, not bytefly. The label and the rule are tuned
|
|
447
|
+
in [`message/config.ts`](../../extensions/bytefly/message/config.ts).
|
|
552
448
|
|
|
553
449
|
## Turn separator
|
|
554
450
|
|
|
@@ -589,11 +485,143 @@ and outcome as the width allows.
|
|
|
589
485
|
rule; disable the whole extension with `bytefly` instead.
|
|
590
486
|
- There is no runtime command; the glyph, label prefix, padding, colors, and
|
|
591
487
|
minimum duration are tuned in
|
|
592
|
-
[`separator/config.ts`](
|
|
488
|
+
[`separator/config.ts`](../../extensions/bytefly/separator/config.ts).
|
|
489
|
+
|
|
490
|
+
## Notices
|
|
491
|
+
|
|
492
|
+
Any extension in the package can post a transcript notice under the shared
|
|
493
|
+
`my-pi-agent/notice` type; bytefly draws it at the transcript's margin — a
|
|
494
|
+
`source · title` headline at the margin, then rail-led rows, each with its own
|
|
495
|
+
severity glyph:
|
|
496
|
+
|
|
497
|
+
```
|
|
498
|
+
job · 2 background jobs finished
|
|
499
|
+
╎ ✓ j1 build · exit 0
|
|
500
|
+
╎ ✕ j2 test · exit 1
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
The rail is painted by the notice's worst severity, so a failure reads red at the
|
|
504
|
+
edge like an errored tool result, and the headline's title takes the notice's own
|
|
505
|
+
severity — a warning reads yellow where its sentence is, while an `info` or `ok`
|
|
506
|
+
notice stays body text. A row's label stays body text too: its severity is the
|
|
507
|
+
glyph it hangs on, so one failing row never tints the rest of the list.
|
|
508
|
+
|
|
509
|
+
`job` and `watch` post one when a background job finishes or a watched line
|
|
510
|
+
matches, so the report the model reads is visible too. `doctor` posts one when a
|
|
511
|
+
hard requirement is missing at session start, with a row per finding and the
|
|
512
|
+
command that fixes it:
|
|
513
|
+
|
|
514
|
+
```
|
|
515
|
+
doctor · 1 missing prerequisite
|
|
516
|
+
╎ ✕ worktree (git) · install git and make sure it is on PATH
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Only a missing *hard* requirement posts a notice at session start; everything
|
|
520
|
+
else waits in the report.
|
|
521
|
+
|
|
522
|
+
The type and the `NoticeDetails` shape are the shared contract in
|
|
523
|
+
[`lib/notice.ts`](../../lib/notice.ts), and the severity glyphs and item cap
|
|
524
|
+
are tuned in [`notice/config.ts`](../../extensions/bytefly/notice/config.ts). Every field is sanitized
|
|
525
|
+
and clipped at the boundary, and a message without `details` keeps Pi's default
|
|
526
|
+
custom-message box.
|
|
527
|
+
|
|
528
|
+
## Compaction
|
|
529
|
+
|
|
530
|
+
`/compact` is Pi's own surface: its summary block is a built-in message
|
|
531
|
+
component, so bytefly cannot replace, hide, or shorten it. The shipped themes
|
|
532
|
+
only remove its fill — `customMessageBg` is the terminal default — and paint the
|
|
533
|
+
`[compaction]` label in the accent, so the block sits on the canvas like the
|
|
534
|
+
rest of the transcript. Pi's branch summaries and skill invocations share the
|
|
535
|
+
same tokens.
|
|
536
|
+
|
|
537
|
+
<img src="../../assets/screens/compaction.png" alt="The /compact summary block: a [compaction] label, the compacted token count, and the summary Markdown on the terminal canvas, with no background band" width="100%">
|
|
538
|
+
|
|
539
|
+
## Tool blocks
|
|
540
|
+
|
|
541
|
+
Every tool block leads with the tool's own call line as the headline — the tool
|
|
542
|
+
name in the theme's tool-title colour — and its result body sits two columns in
|
|
543
|
+
directly beneath it, led by the transcript rail, instead of Pi's filled status
|
|
544
|
+
background:
|
|
545
|
+
|
|
546
|
+
```
|
|
547
|
+
read src/app.ts
|
|
548
|
+
╎ const answer = 42;
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
The two tools that mutate a file, `edit` and `write`, carry their result on the
|
|
552
|
+
call body — the edit diff, the written file content — so that body is railed
|
|
553
|
+
like any other result. There is no status band: the diff's own red/green line
|
|
554
|
+
colours, with the changed words in reverse video, and the `edit` / `write`
|
|
555
|
+
headline are what mark a file change.
|
|
556
|
+
|
|
557
|
+
A `registerToolRenderer` resolver switches the row to `renderShell: "self"`,
|
|
558
|
+
leaves the call's own first line as the headline, and indents the rest of the
|
|
559
|
+
call and the whole result under it. A shell call's `$` / `>` prompt becomes the
|
|
560
|
+
tool name and the command is repainted in the body colour, and a primary subject
|
|
561
|
+
(a path, URL, query, pattern) is demoted to the body colour too, so the name is
|
|
562
|
+
the call line's only accent (`bash bun run check`, `read src/app.ts`). The
|
|
563
|
+
tool's own
|
|
564
|
+
`renderCall`/`renderResult` are passed through, so syntax highlighting, diffs,
|
|
565
|
+
previews, and truncation notices are unchanged — only the frame is bytefly's.
|
|
566
|
+
The body carries the transcript rail, painted by status (a running result takes
|
|
567
|
+
the accent, a failure red, a finished one neutral) and drawn with the glyph from
|
|
568
|
+
the `chrome.rail` setting. A result frame is always railed; a call frame is railed
|
|
569
|
+
only for `edit` and `write`, whose call body carries the result — every other
|
|
570
|
+
call's headline and continuation lines stay plain-indented. Package renderers
|
|
571
|
+
clip a call to one physical line (middle clip for a path or URL), so it cannot
|
|
572
|
+
leak into the body column; Pi's own renderers still wrap, and the frame keeps a
|
|
573
|
+
wrapped continuation unrailed and loses the accent there too, with the rail
|
|
574
|
+
beginning at the result underneath. A rejected call renders as one sanitized
|
|
575
|
+
`error` line in the error role; a running tool shows a live elapsed label, and a
|
|
576
|
+
finished long call appends its duration. A tool with
|
|
577
|
+
no renderer of its own is framed around a generic call/result fallback, whose
|
|
578
|
+
call line reads like a built-in — the leading string argument bare, the rest as
|
|
579
|
+
trailing options (`open_path src/app.ts`) — rather than dumping raw `key=value`
|
|
580
|
+
pairs. A tool that draws its own shell (`edit`) is framed too:
|
|
581
|
+
`renderShell: "self"` only tells Pi not to draw its box around the renderer, so
|
|
582
|
+
its diff would otherwise sit at the wrong indent; the frame drops the blank
|
|
583
|
+
edges its own `Box` pads itself with, and hands it a theme whose `bg` is inert so
|
|
584
|
+
it never paints a band the rest of the transcript does not have.
|
|
585
|
+
|
|
586
|
+
The call line is one colour grammar, shared with Pi's built-ins: the tool name is
|
|
587
|
+
`toolTitle` and bold and is the line's only accent; a primary subject (a query, a
|
|
588
|
+
URL, a path, a status) reads in the body role (`label`), counts and summaries are
|
|
589
|
+
`muted`, trailing options are `dim`, and the result body is `toolOutput`. The
|
|
590
|
+
shipped themes point `toolTitle` at the accent and `label` at the body colour, so
|
|
591
|
+
the name is the call line's one accent and the subject follows as body text; a
|
|
592
|
+
theme that maps `toolTitle` elsewhere is respected rather than overridden.
|
|
593
|
+
|
|
594
|
+
## The working line
|
|
595
|
+
|
|
596
|
+
Pi's working row shows a static `Working`, so a long run reads the same as a
|
|
597
|
+
short one. While the row is up, bytefly advances its message once a second and
|
|
598
|
+
hands it back to Pi when the row comes down. Before the first tool starts it is
|
|
599
|
+
a count:
|
|
600
|
+
|
|
601
|
+
```
|
|
602
|
+
Working… 12s
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
Once a top-level tool starts, the row becomes a live run line: the tool, how
|
|
606
|
+
many top-level tools this run has started, and the elapsed time.
|
|
607
|
+
|
|
608
|
+
```
|
|
609
|
+
edit · 3 tools · 12s
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
A nested tool call (one carrying `parentToolCallId`, such as a codemode script's
|
|
613
|
+
inner call) neither counts nor takes over the line, so the number matches the
|
|
614
|
+
tool blocks in the transcript. The line keeps the last tool name while the
|
|
615
|
+
model streams after it, and a tool event repaints the row immediately instead
|
|
616
|
+
of waiting for the next tick. The line covers the whole run, tool calls
|
|
617
|
+
included. It is tied to the row's visibility: it starts on `turn_start`, stops
|
|
618
|
+
on `agent_end`, and is reset on `session_shutdown`; turns inside one run do not
|
|
619
|
+
restart it, and a retry starts a new run. The words and the interval are tuned
|
|
620
|
+
in [`working/config.ts`](../../extensions/bytefly/working/config.ts).
|
|
593
621
|
|
|
594
622
|
## The control center
|
|
595
623
|
|
|
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%">
|
|
624
|
+
<img src="../../assets/screens/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%">
|
|
597
625
|
|
|
598
626
|
`/bytefly [extension] [refresh]` opens the control center on **Extensions**: a
|
|
599
627
|
keyboard-driven dock list of every extension Pi resolves for the session, so the
|
|
@@ -674,15 +702,21 @@ it. There is nothing to probe, so `r` is not offered here; the metadata is read
|
|
|
674
702
|
once when the section first appears, so an edited `SKILL.md` shows on the next
|
|
675
703
|
open.
|
|
676
704
|
|
|
705
|
+
Themes and prompts have no section of their own, by decision rather than by
|
|
706
|
+
omission: a theme is one active selection — a scalar, global setting — and a
|
|
707
|
+
prompt template is a file Pi discovers from a directory, so neither is a scoped
|
|
708
|
+
enable list this screen's checkbox rows can write. Themes stay with `pi config`;
|
|
709
|
+
`ROADMAP.md` carries the reason under *Deliberately left thin*.
|
|
710
|
+
|
|
677
711
|
**Settings.** The third section uses the same frame and the same `Tab` scope
|
|
678
|
-
switch, with its own cursor. It is the shortlist a session changes:
|
|
712
|
+
switch, with its own cursor. It is the shortlist a session changes: twelve
|
|
679
713
|
preferences on one flat line each, the value beside its label, and no group
|
|
680
714
|
headings. The whole list fits a 24-row terminal, and the frame stops growing
|
|
681
715
|
there however tall the terminal is.
|
|
682
716
|
|
|
683
717
|
```
|
|
684
718
|
Bytefly ──────────────────────────────────────────────────────────────
|
|
685
|
-
Extensions · Skills · Settings Global ·
|
|
719
|
+
Extensions · Skills · Settings Global · 12 settings
|
|
686
720
|
|
|
687
721
|
❯ ◻ Bytefly startup TUI Off
|
|
688
722
|
◼ Theme system
|
|
@@ -692,7 +726,6 @@ Bytefly ────────────────────────
|
|
|
692
726
|
◼ Job finished On
|
|
693
727
|
◼ Watcher matched On
|
|
694
728
|
◻ Wake when a job finishes Off
|
|
695
|
-
◼ Offer the session goal On
|
|
696
729
|
◼ Automatic snapshots On
|
|
697
730
|
◼ Proactive health check On
|
|
698
731
|
Currency CNY (¥)
|
|
@@ -706,7 +739,7 @@ Bytefly ────────────────────────
|
|
|
706
739
|
──────────────────────────────────────────────────────────────────────
|
|
707
740
|
```
|
|
708
741
|
|
|
709
|
-
<img src="../../assets/bytefly-settings.png" alt="The /bytefly Settings section: one flat list of
|
|
742
|
+
<img src="../../assets/screens/bytefly-settings.png" alt="The /bytefly Settings section: one flat list of twelve preferences with each value beside its label, the `Global · 12 settings` counts, and a three-row detail pane naming the focused row's source, description, and file" width="100%">
|
|
710
743
|
|
|
711
744
|
| Row | Source | Values |
|
|
712
745
|
|---|---|---|
|
|
@@ -718,7 +751,6 @@ Bytefly ────────────────────────
|
|
|
718
751
|
| Job finished | `notify.jobFinished` | Off, On |
|
|
719
752
|
| Watcher matched | `notify.matchFound` | Off, On |
|
|
720
753
|
| Wake when a job finishes | `job.wakeOnFinish` | Off, On |
|
|
721
|
-
| Offer the session goal | `plan.goalPrompt` | Off, On |
|
|
722
754
|
| Automatic snapshots | `rewind.autoSnapshots` | Off, On |
|
|
723
755
|
| Proactive health check | `doctor.proactive` | Off, On |
|
|
724
756
|
| Currency | `price.currency.code` | CNY, USD |
|
|
@@ -751,20 +783,20 @@ shows where the value comes from — `Global · ~/.pi/agent/bytefly.json`, `Proj
|
|
|
751
783
|
— even when the terminal is too short for the detail body — and closing offers
|
|
752
784
|
the same reload confirm as an extension or skill toggle.
|
|
753
785
|
|
|
754
|
-
The list is capped at
|
|
786
|
+
The list is capped at twelve rows so the screen keeps fitting a 24-row
|
|
755
787
|
terminal: adding a setting means removing one (`panel/panel.test.ts` holds the
|
|
756
788
|
ceiling). Everything else stays in `bytefly.json` — the tuning numbers, the
|
|
757
789
|
cosmetic labels, and the Pi preferences Pi's own `/settings` owns — and
|
|
758
790
|
`test/settings-coverage.test.ts` keeps the split honest: every loader key is
|
|
759
|
-
either a row or a declared JSON-only edit with the reason it left.
|
|
760
|
-
`bytefly.json` sections therefore have no row at all
|
|
761
|
-
`worktree`, `memory`
|
|
791
|
+
either a row or a declared JSON-only edit with the reason it left. Most
|
|
792
|
+
`bytefly.json` sections therefore have no row at all — `chrome`, `goal`, `watch`,
|
|
793
|
+
`worktree`, and `memory` among them — just as `notify.title`, `doctor.timeoutMs`,
|
|
762
794
|
`price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`,
|
|
763
795
|
`job.detachedByDefault`, and `watch.wakeOnMatch` inside sections that do. Each is
|
|
764
|
-
documented in [`docs/configuration.md`](
|
|
796
|
+
documented in [`docs/configuration.md`](../configuration.md).
|
|
765
797
|
|
|
766
|
-
|
|
767
|
-
|
|
798
|
+
Two of the five sections belong to other extensions (`rewind` and `job`). The
|
|
799
|
+
screen cannot import their normalizers, so it reports the leaf as
|
|
768
800
|
the file states it and declares the loader's default; the same test holds the
|
|
769
801
|
catalogue to every loader's defaults and bounds in both directions.
|
|
770
802
|
|
|
@@ -776,7 +808,7 @@ with `true` or `false`.
|
|
|
776
808
|
|
|
777
809
|
App rows are **Global only**: Pi's setters for them write the personal
|
|
778
810
|
`settings.json`, and only resource paths have public project setters. Project
|
|
779
|
-
scope therefore lists the
|
|
811
|
+
scope therefore lists the ten `bytefly.json` rows and a
|
|
780
812
|
`App settings are Global only.` note rather than promising a write that cannot
|
|
781
813
|
happen. A `bytefly.json` row writes one leaf in the selected scope (a depth-1
|
|
782
814
|
key, or a nested one such as `price.currency.code`) through a per-key writer, so
|
|
@@ -788,16 +820,19 @@ The non-`tui` form prints the headline and one `Label: Value` row per line, in
|
|
|
788
820
|
screen order:
|
|
789
821
|
|
|
790
822
|
```
|
|
791
|
-
bytefly: Settings · Global ·
|
|
823
|
+
bytefly: Settings · Global · 12 settings
|
|
792
824
|
Bytefly startup TUI: Off
|
|
793
|
-
Theme:
|
|
794
|
-
Desktop notifications:
|
|
825
|
+
Theme: bytefly-dark
|
|
826
|
+
Desktop notifications: On
|
|
795
827
|
Turn finished: On
|
|
796
828
|
Needs input: On
|
|
797
829
|
Job finished: On
|
|
798
830
|
Watcher matched: On
|
|
799
|
-
|
|
800
|
-
|
|
831
|
+
Wake when a job finishes: On
|
|
832
|
+
Automatic snapshots: On
|
|
833
|
+
Proactive health check: On
|
|
834
|
+
Currency: CNY (¥)
|
|
835
|
+
Session budget: 5
|
|
801
836
|
```
|
|
802
837
|
|
|
803
838
|
The doctor side probes every declared extension and reports each check as `ok`,
|
|
@@ -860,7 +895,7 @@ has a keyboard path.
|
|
|
860
895
|
| rewind | `git` | — |
|
|
861
896
|
| document | — | — |
|
|
862
897
|
| subagent | a runnable nested `pi` | project-local agents need a trusted project |
|
|
863
|
-
| plan | — |
|
|
898
|
+
| plan | — | an interactive UI |
|
|
864
899
|
| memory | — | `git` for the project-scope root |
|
|
865
900
|
| file-browse | — | `git` for the branch chip; the browser opener is best-effort |
|
|
866
901
|
| web-access | — | `unpdf` |
|
|
@@ -877,10 +912,10 @@ the same entry in `lib/requirements.ts`, so the two cannot drift.
|
|
|
877
912
|
|
|
878
913
|
## Notifications
|
|
879
914
|
|
|
880
|
-
The notify capability exists for unattended runs: start a
|
|
881
|
-
terminal, and get a desktop notification when Pi needs you
|
|
882
|
-
It fires on four events, each independently switchable in
|
|
883
|
-
of `bytefly.json` (see [Configuration](#configuration)):
|
|
915
|
+
The notify capability is off by default and exists for unattended runs: start a
|
|
916
|
+
long turn, leave the terminal, and get a desktop notification when Pi needs you
|
|
917
|
+
— or when it is done. It fires on four events, each independently switchable in
|
|
918
|
+
the `notify` section of `bytefly.json` (see [Configuration](#configuration)):
|
|
884
919
|
|
|
885
920
|
- **A run settled** (`agent_settled`). Pi finished the turn and waits for the
|
|
886
921
|
next message. An aborted run is skipped: interrupting with Escape means the
|
|
@@ -889,15 +924,15 @@ of `bytefly.json` (see [Configuration](#configuration)):
|
|
|
889
924
|
`ask_user_question`, a plan review, a subagent approval. A prompt opened while
|
|
890
925
|
idle is a command the user just typed, so it does not fire; the run boundary
|
|
891
926
|
is what separates "the agent is asking" from "the user is asking".
|
|
892
|
-
- **A background job finished.** The [job](
|
|
927
|
+
- **A background job finished.** The [job](./job.md) extension announces each
|
|
893
928
|
terminal transition on the shared `pi.events` bus
|
|
894
929
|
(`my-pi-agent/job-finished`); bytefly listens and never imports it.
|
|
895
|
-
- **A watcher matched.** A [watch](
|
|
896
|
-
|
|
930
|
+
- **A watcher matched.** A [watch](./watch.md) whose `wake` is on matched, and
|
|
931
|
+
announced it on `my-pi-agent/watch-match` with the cycle's
|
|
897
932
|
count, the watcher, and its newest line. The body names that line, sanitized and
|
|
898
933
|
clipped to 80 characters, because the line is the alert: a watch usually tails a
|
|
899
|
-
build or an error log. A match the agent was busy for
|
|
900
|
-
|
|
934
|
+
build or an error log. A match the agent was busy for notifies once that run
|
|
935
|
+
settles, when its wake is raised.
|
|
901
936
|
|
|
902
937
|
### Delivery method
|
|
903
938
|
|
|
@@ -1011,17 +1046,27 @@ release without a restart. Opening the control center never checks: the screen h
|
|
|
1011
1046
|
no update surface, and the only request paths are `session_start` and this
|
|
1012
1047
|
command.
|
|
1013
1048
|
|
|
1049
|
+
`/bytefly upgrade` is the half that writes. It asks for a confirmation and then
|
|
1050
|
+
calls the package manager's own `update()`: the same manager that reads the
|
|
1051
|
+
packages configured in `settings.json`, owns the install root, and honours a
|
|
1052
|
+
project's `npmCommand`, so no shell and no `pi update` command is involved. Pi
|
|
1053
|
+
skips a pinned npm version, and `PI_OFFLINE` skips the whole path. The manager
|
|
1054
|
+
returns nothing, so the answer is a re-read of what is left: `every configured
|
|
1055
|
+
package is updated — reload to use the new version`, or a warning when a package
|
|
1056
|
+
is still behind after a successful run; a failed install prints the manager's own
|
|
1057
|
+
message. The running session keeps the old code loaded until it reloads, which is
|
|
1058
|
+
why the line says so, and each source the manager reports is shown while it runs.
|
|
1059
|
+
|
|
1014
1060
|
## Limitations
|
|
1015
1061
|
|
|
1016
1062
|
- **Bytefly startup TUI is the startup surface only.** It installs or removes
|
|
1017
1063
|
bytefly's startup header and the proactive doctor notice; the footer, turn
|
|
1018
1064
|
rule, and transcript renderers stay on. Use `PI_DISABLED_EXTENSIONS=bytefly`
|
|
1019
1065
|
(or `pi config`) to turn off all of bytefly.
|
|
1020
|
-
- **App settings are Global only.** Pi's setters for
|
|
1021
|
-
`quietStartup` (the **Bytefly startup TUI** row)
|
|
1022
|
-
`
|
|
1023
|
-
|
|
1024
|
-
manage.
|
|
1066
|
+
- **App settings are Global only.** Pi's setters for the two app preferences
|
|
1067
|
+
the screen carries — `quietStartup` (the **Bytefly startup TUI** row) and
|
|
1068
|
+
`theme` — write the personal `settings.json`; the screen hides those rows in
|
|
1069
|
+
Project scope rather than writing a file Pi cannot manage.
|
|
1025
1070
|
- **The Theme row offers only this package's palettes.** `system`,
|
|
1026
1071
|
`bytefly-dark`, and `bytefly-light` are the whole cycle; Pi's built-ins and any
|
|
1027
1072
|
user, project, or other package's theme stay in Pi's `/settings` → **Theme**,
|
|
@@ -1034,7 +1079,7 @@ command.
|
|
|
1034
1079
|
- **The list is a shortlist, not the whole document.** A row is one boolean,
|
|
1035
1080
|
enum, string, or number; the tuning numbers, the labels, and the Pi
|
|
1036
1081
|
preferences `/settings` owns stay in their files, and the catalogue is capped
|
|
1037
|
-
at
|
|
1082
|
+
at twelve rows so the screen fits a 24-row terminal. `doctor.skip` (an
|
|
1038
1083
|
array), the `rates` table, and `price.peak` (a nested object) could never be a
|
|
1039
1084
|
row; the rest are declared JSON-only with their reason in
|
|
1040
1085
|
`test/settings-coverage.test.ts`.
|
|
@@ -1042,16 +1087,18 @@ command.
|
|
|
1042
1087
|
because a two-column glyph would push every railed body one cell right; the
|
|
1043
1088
|
loader drops anything else, and the former four-glyph menu is the
|
|
1044
1089
|
configuration reference's example list.
|
|
1045
|
-
- **`doctor`, `settings`, `skills`, and `
|
|
1046
|
-
`/bytefly doctor` always selects the report, so an extension
|
|
1047
|
-
`doctor` cannot be narrowed to by name; `settings`, `skills`,
|
|
1048
|
-
reserved the same way.
|
|
1090
|
+
- **`doctor`, `settings`, `skills`, `update`, and `upgrade` are reserved first
|
|
1091
|
+
arguments.** `/bytefly doctor` always selects the report, so an extension
|
|
1092
|
+
literally named `doctor` cannot be narrowed to by name; `settings`, `skills`,
|
|
1093
|
+
`update`, and `upgrade` are reserved the same way.
|
|
1049
1094
|
- **The picker manages the `extensions` and `skills` resource types.** Prompts
|
|
1050
1095
|
and themes stay with Pi's own `pi config`.
|
|
1051
1096
|
- **Built-in extensions are not listed** (`builtin:mcp`, `builtin:codemode`, …):
|
|
1052
1097
|
their authoritative names are not exposed to extensions. Use `pi config`.
|
|
1053
|
-
- **
|
|
1054
|
-
|
|
1098
|
+
- **Nothing is installed or removed here.** `/bytefly upgrade` runs Pi's own
|
|
1099
|
+
update for the packages configured in `settings.json`; adding a package is
|
|
1100
|
+
still `pi install`, removing one is `pi remove`, and Pi itself is still
|
|
1101
|
+
`pi update`.
|
|
1055
1102
|
- **The update list is Pi's.** Only packages configured in `settings.json` are
|
|
1056
1103
|
checked; `pi -e .`, a temporary checkout, and other unmanaged loads get no
|
|
1057
1104
|
update prompt. The version arrow and release URL still come from npm's
|
|
@@ -1070,7 +1117,9 @@ command.
|
|
|
1070
1117
|
restores both on shutdown. A future Pi that changes either method shape makes
|
|
1071
1118
|
that shim inert, and Pi's own block can come back.
|
|
1072
1119
|
- **No auto-update, and the release URL is text only.** The notice names a
|
|
1073
|
-
command instead of running one
|
|
1120
|
+
command instead of running one; the only path that writes is `/bytefly
|
|
1121
|
+
upgrade`, and it waits for a confirmation. The notice renderer cannot open a
|
|
1122
|
+
link, so
|
|
1074
1123
|
the release row prints the URL and nothing more — no changelog body, no way to
|
|
1075
1124
|
click through from the transcript. Pi's optional release note arrives as one
|
|
1076
1125
|
sanitized `release notes` row, so a multi-paragraph note is flattened and
|
|
@@ -1140,7 +1189,7 @@ command.
|
|
|
1140
1189
|
`bytefly.json`.
|
|
1141
1190
|
- No per-model cost breakdown and no on-screen marker for which tariff or
|
|
1142
1191
|
which source produced a number.
|
|
1143
|
-
- No todo-count segment; the [todo](
|
|
1192
|
+
- No todo-count segment; the [todo](./todo.md) widget already shows progress.
|
|
1144
1193
|
- No shelling out for git ahead/behind; the footer data provider exposes only
|
|
1145
1194
|
the branch.
|
|
1146
1195
|
- No session or model data in the header: it shows the nameplate and the grouped
|
|
@@ -1180,12 +1229,12 @@ rather than showing a wrong value.
|
|
|
1180
1229
|
| Notifications | `agent_settled` (skipped when aborted), `ui_prompt_start` only while `agent_start`…`agent_settled` marks a run active, and `my-pi-agent/job-finished` on `pi.events`; the `notify` section of `bytefly.json` gates each. Delivery writes an OSC 777/99 sequence to stdout or spawns `osascript`, `notify-send`, or `powershell.exe`. The bus subscription is created in `session_start` and released in `session_shutdown`, and the `job` extension never imports bytefly. |
|
|
1181
1230
|
| Picker discovery | `SettingsManager.create(...)` plus `DefaultPackageManager.resolve({ onMissing: "skip" })`, both public exports; both views drop `bytefly`'s own entrypoint. |
|
|
1182
1231
|
| Picker writes | `SettingsManager` setters (`setExtensionPaths`, `setPackages`, `setProjectExtensionPaths`, `setProjectPackages`) then `flush()`; `ctx.reload()` after the screen closes when changes are pending. |
|
|
1183
|
-
| Settings writes | App rows call `SettingsManager` setters (`setQuietStartup`, `
|
|
1232
|
+
| Settings writes | App rows call `SettingsManager` setters (`setQuietStartup`, `setTheme`) on the global store and `flush()`, then surface `drainErrors()`; `bytefly.json` rows call `writeConfigValuesAt` on the selected scope's document with the row's leaf path, so a nested key (`price.currency.decimals`) and a flat one (`notify.method`) share one writer, and a row that also writes a companion leaf (the currency and its default precision) applies both in one document pass; and `u` calls `unsetConfigValueAt` with the same path. A failed or refused write shows a notice in the screen's hint row and leaves the displayed value unchanged; a successful one marks the screen dirty. |
|
|
1184
1233
|
| 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. |
|
|
1185
1234
|
| 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. |
|
|
1186
1235
|
| 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. |
|
|
1187
1236
|
| 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. |
|
|
1188
|
-
| 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`;
|
|
1237
|
+
| 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`; `/bytefly upgrade` calls `UpdateHandle.apply()`, which runs `applyUpdates()` — Pi's `DefaultPackageManager.update()`, with its progress passed to `ctx.ui.notify` — and then re-reads the snapshot so the marker cannot outlive the version it named. 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. |
|
|
1189
1238
|
| 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. |
|
|
1190
1239
|
| Data sources | `footerData.getGitBranch()`, `footerData.getAvailableProviderCount()`, `ctx.getContextUsage()`, `ctx.sessionManager.getEntries()`, `ctx.sessionManager.getSessionName()`, `ctx.model`; subscribes to `footerData.onBranchChange` to repaint. |
|
|
1191
1240
|
| 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`. |
|
|
@@ -1299,7 +1348,7 @@ rather than showing a wrong value.
|
|
|
1299
1348
|
`worktree` and `browse` are location, so the `◉ <port>` chip sits beside `⎇`
|
|
1300
1349
|
branch and `⑂` worktree and the left zone stays the filesystem identity; a
|
|
1301
1350
|
plan or a failed job is mode or alert, so it takes the slot after the gauge.
|
|
1302
|
-
The [wechat](
|
|
1351
|
+
The [wechat](./wechat.md) extension publishes `✆ wechat` while its bridge runs,
|
|
1303
1352
|
which is why the bar has to render `getExtensionStatuses()` at all.
|
|
1304
1353
|
- **Segments degrade; they do not clip.** Each `Segment` carries progressively
|
|
1305
1354
|
shorter `forms` and a `weight`; the layout advances the lowest-priority form
|
|
@@ -1495,10 +1544,10 @@ columns, gauge), so the look follows the active theme.
|
|
|
1495
1544
|
| `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the words, the tool singular/plural, and the tick interval. |
|
|
1496
1545
|
| `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape: the plain count and the `tool · N tools · elapsed` run line. |
|
|
1497
1546
|
| `working/register.ts` | Starts the tick on `turn_start`, tracks top-level tools on `tool_execution_start`, and cancels on `agent_end`/`session_shutdown`. |
|
|
1498
|
-
| `panel/types.ts` | `PanelSection` (`extensions`
|
|
1547
|
+
| `panel/types.ts` | `PanelSection` (`extensions` \| `skills` \| `settings`), `PanelRow` with its optional skill info, `SkillInfo`, and `PanelModel`, the merged row model. |
|
|
1499
1548
|
| `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`. |
|
|
1500
1549
|
| `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. |
|
|
1501
|
-
| `panel/settings.ts` | The curated Settings catalogue: the
|
|
1550
|
+
| `panel/settings.ts` | The curated Settings catalogue: the twelve 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. |
|
|
1502
1551
|
| `panel/settings-runtime.ts` | The Settings runtime: snapshot cache, scope guards, app setters, per-leaf `bytefly.json` writes, dirty state, and change listeners. |
|
|
1503
1552
|
| `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. |
|
|
1504
1553
|
| `panel/skills.ts` | Skill metadata through Pi's own `loadSkills`, keyed by resolved path, plus the deduplicated paths both discovery views read. |
|