@gavin-hu/my-pi-agent 0.18.0 → 0.20.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 +66 -52
- package/README.zh-CN.md +56 -46
- package/docs/extensions/README.md +34 -0
- package/docs/extensions/board.md +507 -0
- package/{extensions/bytefly/README.md → docs/extensions/bytefly.md} +774 -574
- 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 +561 -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} +62 -52
- package/{extensions/memory/README.md → docs/extensions/memory.md} +71 -60
- package/{extensions/plan/README.md → docs/extensions/plan.md} +440 -322
- package/{extensions/question/README.md → docs/extensions/question.md} +54 -31
- package/{extensions/rewind/README.md → docs/extensions/rewind.md} +115 -122
- package/docs/extensions/session-bus.md +298 -0
- package/{extensions/subagent/README.md → docs/extensions/subagent.md} +165 -118
- package/docs/extensions/team.md +254 -0
- package/{extensions/todo/README.md → docs/extensions/todo.md} +85 -88
- package/{extensions/watch/README.md → docs/extensions/watch.md} +54 -36
- package/{extensions/web-access/README.md → docs/extensions/web-access.md} +93 -50
- package/{extensions/wechat/README.md → docs/extensions/wechat.md} +260 -163
- package/{extensions/worktree/README.md → docs/extensions/worktree.md} +137 -79
- package/extensions/board/commands.ts +105 -0
- package/extensions/board/config.ts +36 -0
- package/extensions/board/format.ts +170 -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 +388 -0
- package/extensions/board/result.ts +108 -0
- package/extensions/board/rows.ts +48 -0
- package/extensions/board/schema.ts +90 -0
- package/extensions/board/seat.ts +28 -0
- package/extensions/board/snapshot.ts +42 -0
- package/extensions/board/tools.ts +444 -0
- package/extensions/board/transport/router.ts +91 -0
- package/extensions/board/transport/server.ts +138 -0
- package/extensions/board/types.ts +121 -0
- package/extensions/board/view/client.ts +51 -0
- package/extensions/board/view/dialog.ts +43 -0
- package/extensions/board/view/keys.ts +125 -0
- package/extensions/board/view/live.ts +231 -0
- package/extensions/board/view/names.ts +91 -0
- package/extensions/board/view/page.ts +118 -0
- package/extensions/board/view/render.ts +519 -0
- package/extensions/board/view/styles.ts +228 -0
- package/extensions/board/view/team.ts +327 -0
- package/extensions/bytefly/footer/budget.ts +6 -5
- package/extensions/bytefly/footer/collect/entries.ts +12 -4
- package/extensions/bytefly/footer/collect/snapshot.ts +8 -17
- package/extensions/bytefly/footer/config.ts +19 -8
- package/extensions/bytefly/footer/price/price.ts +30 -8
- package/extensions/bytefly/footer/register.ts +5 -5
- package/extensions/bytefly/footer/render/format.ts +18 -0
- package/extensions/bytefly/footer/render/lines.ts +23 -7
- package/extensions/bytefly/footer/render/segments.ts +117 -31
- package/extensions/bytefly/footer/types.ts +29 -5
- package/extensions/bytefly/footer/unpriced.ts +42 -17
- package/extensions/bytefly/panel/commands.ts +67 -7
- package/extensions/bytefly/panel/filter.ts +68 -0
- package/extensions/bytefly/panel/format.ts +16 -15
- package/extensions/bytefly/panel/join.ts +56 -13
- package/extensions/bytefly/panel/prices.ts +43 -0
- package/extensions/bytefly/panel/settings-runtime.ts +0 -6
- package/extensions/bytefly/panel/settings.ts +75 -43
- package/extensions/bytefly/panel/tui/entries.ts +26 -8
- package/extensions/bytefly/panel/tui/frame.ts +130 -93
- package/extensions/bytefly/panel/tui/keys.ts +352 -0
- package/extensions/bytefly/panel/tui/list-view.ts +25 -46
- package/extensions/bytefly/panel/tui/panes.ts +76 -0
- package/extensions/bytefly/panel/tui/section-view.ts +126 -0
- package/extensions/bytefly/panel/tui/settings-section.ts +54 -125
- package/extensions/bytefly/panel/tui/settings-view.ts +30 -131
- package/extensions/bytefly/panel/tui/side-pane.ts +224 -0
- package/extensions/bytefly/panel/tui.ts +306 -259
- 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/check/commands.ts +2 -1
- package/extensions/context/tui.ts +1 -1
- package/extensions/file-browse/{config.ts → config/config.ts} +1 -1
- package/extensions/file-browse/files/classify.ts +136 -0
- package/extensions/file-browse/files/files.ts +12 -0
- package/extensions/file-browse/files/index.ts +90 -0
- package/extensions/file-browse/files/list.ts +261 -0
- package/extensions/file-browse/{paths.ts → files/paths.ts} +1 -1
- package/extensions/file-browse/files/tree.ts +101 -0
- 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} +20 -69
- package/extensions/file-browse/{router.ts → transport/router.ts} +21 -17
- package/extensions/file-browse/transport/server.ts +110 -0
- package/extensions/file-browse/{chrome.ts → view/chrome.ts} +4 -4
- package/extensions/file-browse/{client.ts → view/client.ts} +1 -1
- package/extensions/file-browse/{diff-html.ts → view/diff-html.ts} +3 -3
- package/extensions/file-browse/view/emit.ts +51 -0
- package/extensions/file-browse/{html.ts → view/html.ts} +19 -18
- package/extensions/file-browse/{icons.ts → view/icons.ts} +1 -1
- package/extensions/file-browse/{markdown.ts → view/markdown.ts} +18 -20
- package/extensions/file-browse/{raw-html.ts → view/raw-html.ts} +19 -14
- package/extensions/file-browse/{styles.ts → view/styles.ts} +29 -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/job/runtime.ts +4 -4
- package/extensions/memory/store.ts +12 -5
- package/extensions/plan/blocks.ts +23 -2
- package/extensions/plan/commands.ts +21 -16
- package/extensions/plan/feedback.ts +185 -52
- package/extensions/plan/format.ts +10 -3
- package/extensions/plan/index.ts +23 -5
- package/extensions/plan/plan-files.ts +88 -0
- package/extensions/plan/plan-index.ts +43 -9
- package/extensions/plan/plan-text.ts +33 -23
- package/extensions/plan/plans.ts +27 -34
- package/extensions/plan/policy.ts +30 -17
- package/extensions/plan/review.ts +3 -27
- package/extensions/plan/runtime.ts +52 -11
- package/extensions/plan/sections.ts +112 -0
- package/extensions/plan/steps.ts +3 -22
- package/extensions/plan/todos.ts +51 -3
- package/extensions/plan/tools/exit.ts +20 -95
- package/extensions/plan/tools/todo-seed.ts +4 -2
- package/extensions/plan/tools/write.ts +12 -1
- package/extensions/plan/tui.ts +5 -34
- package/extensions/plan/types.ts +15 -8
- package/extensions/plan/web-blocks.ts +89 -0
- package/extensions/plan/web-chrome.ts +3 -5
- package/extensions/plan/web-client.ts +179 -330
- package/extensions/plan/web-collab.ts +3 -3
- package/extensions/plan/web-comments.ts +18 -8
- package/extensions/plan/web-composer.ts +80 -0
- package/extensions/plan/web-draft.ts +40 -0
- package/extensions/plan/web-keys.ts +134 -0
- package/extensions/plan/web-outline.ts +192 -0
- package/extensions/plan/web-page.ts +4 -8
- package/extensions/plan/web-plan.ts +150 -0
- package/extensions/plan/web-router.ts +3 -58
- package/extensions/plan/web-settle.ts +194 -0
- package/extensions/plan/web-share-session.ts +24 -30
- package/extensions/plan/web-streams.ts +14 -14
- package/extensions/plan/web-tokens.ts +2 -2
- package/extensions/plan/web.ts +66 -120
- package/extensions/rewind/{commands.ts → commands/commands.ts} +5 -5
- package/extensions/rewind/{review.ts → commands/review.ts} +15 -14
- 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 +17 -69
- package/extensions/session-bus/format.ts +22 -45
- package/extensions/session-bus/index.ts +13 -7
- package/extensions/session-bus/join-request.ts +40 -0
- package/extensions/session-bus/mail-watch.ts +134 -0
- package/extensions/session-bus/notice.ts +32 -4
- package/{lib/claims → extensions/session-bus}/overlap.ts +11 -18
- package/extensions/session-bus/protocol.ts +19 -49
- package/extensions/session-bus/resolve.ts +67 -0
- package/extensions/session-bus/result.ts +16 -51
- package/extensions/session-bus/rows.ts +11 -5
- package/extensions/session-bus/runtime.ts +220 -267
- package/extensions/session-bus/store.ts +55 -7
- package/extensions/session-bus/tools.ts +31 -66
- package/extensions/session-bus/tui.ts +5 -5
- package/extensions/session-bus/types.ts +23 -14
- package/extensions/subagent/agents.ts +9 -8
- package/extensions/subagent/commands.ts +2 -1
- package/extensions/subagent/invocation.ts +4 -2
- package/extensions/team/commands.ts +145 -0
- package/extensions/team/dispatch.ts +133 -0
- package/extensions/team/format.ts +119 -0
- package/extensions/team/index.ts +34 -0
- package/extensions/team/schema.ts +29 -0
- package/extensions/team/tools.ts +267 -0
- package/extensions/team/types.ts +65 -0
- package/extensions/todo/index.ts +4 -1
- package/extensions/todo/nudge.ts +8 -2
- 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 +106 -251
- 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} +37 -37
- package/extensions/wechat/{prompt.ts → dialog/prompt.ts} +2 -2
- package/extensions/wechat/{remote-ui.ts → dialog/remote-ui.ts} +1 -1
- package/extensions/wechat/index.ts +10 -10
- package/extensions/wechat/intake.ts +245 -0
- 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} +100 -22
- package/extensions/wechat/{presence.ts → peer/presence.ts} +8 -7
- package/extensions/wechat/{reply-pipeline.ts → peer/reply-pipeline.ts} +1 -1
- 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} +8 -0
- 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} +72 -28
- 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/commands.ts +24 -17
- package/extensions/worktree/exit.ts +12 -6
- package/extensions/worktree/git.ts +22 -14
- package/extensions/worktree/guard.ts +18 -290
- package/extensions/worktree/handoff.ts +10 -2
- package/extensions/worktree/index.ts +2 -1
- package/extensions/worktree/lifecycle.ts +2 -0
- package/extensions/worktree/registry.ts +20 -11
- package/extensions/worktree/root-tools.ts +13 -3
- package/extensions/worktree/runtime.ts +8 -2
- package/extensions/worktree/screen.ts +15 -8
- package/extensions/worktree/shell.ts +303 -0
- package/extensions/worktree/state.ts +1 -1
- package/extensions/worktree/status.ts +42 -9
- package/extensions/worktree/tools.ts +19 -13
- package/lib/README.md +11 -8
- package/lib/board/card.ts +479 -0
- package/lib/board/links.ts +141 -0
- package/lib/board/page-pointer.ts +310 -0
- package/lib/board/round-text.ts +81 -0
- package/lib/board/round.ts +94 -0
- package/lib/board/rules.ts +437 -0
- package/lib/board/session.ts +105 -0
- package/lib/board/store.ts +497 -0
- package/lib/board/view.ts +234 -0
- package/lib/errors.ts +12 -4
- package/lib/format.ts +35 -0
- package/lib/http/guard.ts +112 -0
- package/lib/http/index.ts +16 -5
- package/lib/http/serve.ts +237 -0
- package/lib/http/server.ts +12 -10
- package/lib/http/sink.ts +135 -0
- package/lib/http/token.ts +38 -0
- package/lib/plan-entry.ts +11 -0
- package/lib/policy.ts +25 -2
- package/lib/requirements.ts +6 -7
- package/lib/session-label.ts +64 -0
- package/lib/session-roster.ts +201 -0
- package/lib/session-tool.ts +184 -0
- package/lib/spawn.ts +37 -3
- package/lib/stray-fields.ts +45 -0
- package/lib/tool-names.ts +38 -2
- package/lib/tui/glyphs.ts +3 -2
- package/lib/web/README.md +57 -4
- package/lib/web/client-runtime.ts +123 -0
- package/lib/web/components.ts +5 -0
- package/lib/web/index.ts +4 -2
- package/lib/web/markup.ts +88 -1
- package/lib/web/names.ts +42 -0
- package/lib/web/runtime.ts +7 -1
- package/lib/web/tokens.ts +25 -2
- package/package.json +26 -14
- package/skills/next/SKILL.md +4 -3
- 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/bytefly/panel/tui/extensions-view.ts +0 -40
- package/extensions/bytefly/panel/tui/skills-view.ts +0 -50
- package/extensions/file-browse/README.md +0 -506
- package/extensions/file-browse/files.ts +0 -564
- package/extensions/file-browse/server.ts +0 -141
- package/extensions/job/process.ts +0 -35
- package/extensions/plan/split.ts +0 -87
- package/extensions/session-bus/README.md +0 -247
- package/extensions/session-bus/team.ts +0 -102
- package/extensions/wechat/outbound.ts +0 -100
- package/lib/plans/sections.ts +0 -172
- package/lib/plans/setting.ts +0 -52
- package/lib/plans/split.ts +0 -215
- package/lib/plans/store.ts +0 -19
- package/lib/plans/team.ts +0 -151
- package/skills/changelog/SKILL.md +0 -148
- package/skills/parallel-dev/SKILL.md +0 -150
- /package/extensions/file-browse/{rev.ts → live/rev.ts} +0 -0
- /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/{live-client.ts → view/live-client.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,364 +1,109 @@
|
|
|
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:
|
|
11
|
+
## Capabilities
|
|
100
12
|
|
|
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:
|
|
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.
|
|
121
14
|
|
|
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.
|
|
198
|
-
|
|
199
|
-
```
|
|
200
|
-
edit · 3 tools · 12s
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
A nested tool call (one carrying `parentToolCallId`, such as a codemode script's
|
|
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 | State on one line — location, modes, and alerts — and meters on the other — context, spend, tokens, cache, and model — each shedding parts rather than clipping. | Shipped |
|
|
21
|
+
| Extension status chips | `footerData.getExtensionStatuses()` | Worktree, browse, plan, and alert statuses appear in the footer, using each extension's own colour. A failed job is the one chip no width drops. | 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
|
+
| One frame, three sections | `/bytefly`, `/bytefly skills`, `/bytefly settings` | Extensions, skills, and settings in one dock: the worst problem in the header, each section's count on the tabs, the write scope at the right, and one body height for all three, so changing section never resizes the screen. | Shipped |
|
|
36
|
+
| Resource rows and the block | `Space`, `Enter`, `?` | A name-first row — `worktree`, not `worktree/index.ts` — with one checkbox, one status glyph and one verdict word, and the focused row's findings, path, source, state, and health beside the list at 96 columns and under it below. | Shipped |
|
|
37
|
+
| Grouped settings | `/bytefly settings` | Twelve preferences under `Startup`, `Notifications`, `Session`, and `Price`, each value in one aligned column and editable in place; `J` shows the stored JSON section. | Shipped |
|
|
38
|
+
| 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 |
|
|
39
|
+
| Filters and scope | `/`, `!`, `s`, `x` | Narrow the rows by text or to what needs attention — the chips on the tab row say which — and choose where a toggle lands, the personal or project `settings.json`, with `x` clearing a project override. | Shipped |
|
|
40
|
+
| Reload after changes | `R` | `unsaved changes` joins the header while a write is pending, and `R` reloads to apply it 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` | The session total shows as `spent/limit` in the footer, and one notice plus one OS notification fires when it reaches the threshold. | Partial |
|
|
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
|
-
|
|
64
|
+
```text
|
|
65
|
+
/bytefly # the control center, on Extensions
|
|
66
|
+
/bytefly doctor # the report run_doctor returns
|
|
240
67
|
```
|
|
241
|
-
doctor · 1 missing prerequisite
|
|
242
|
-
╎ ✕ worktree (git) · install git and make sure it is on PATH
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
The type and the `NoticeDetails` shape are the shared contract in
|
|
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
68
|
|
|
251
|
-
|
|
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.
|
|
69
|
+
## Tool
|
|
257
70
|
|
|
258
|
-
<img src="../../assets/
|
|
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%">
|
|
259
72
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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.
|
|
264
79
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
The two tools that mutate a file, `edit` and `write`, carry their result on 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.
|
|
275
|
-
|
|
276
|
-
A `registerToolRenderer` resolver switches the row to `renderShell: "self"`,
|
|
277
|
-
leaves the call's own first line as the headline, and indents the rest of the
|
|
278
|
-
call and the whole result under it. A shell call's `$` / `>` prompt becomes the
|
|
279
|
-
tool name and the command is repainted in the body colour, and a primary subject
|
|
280
|
-
(a path, URL, query, pattern) is demoted to the body colour too, so the name is
|
|
281
|
-
the call line's only accent (`bash bun run check`, `read src/app.ts`). The
|
|
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.
|
|
304
|
-
|
|
305
|
-
The call line is one colour grammar, shared with Pi's built-ins: the tool name is
|
|
306
|
-
`toolTitle` and bold and is the line's only accent; a primary subject (a query, a
|
|
307
|
-
URL, a path, a status) reads in the body role (`label`), counts and summaries are
|
|
308
|
-
`muted`, trailing options are `dim`, and the result body is `toolOutput`. The
|
|
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
|
-
an armed `watch` wake match fires as the agent becomes 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. |
|
|
355
97
|
| `/bytefly settings` | Open the control center on Settings. Outside `tui` it prints one `Label: Value` line per setting. |
|
|
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. |
|
|
100
|
+
| `/bytefly prices` | Name the models this session could not price: the `price.rates` key for each, the records behind it, and where to add it. It prices the session when asked, so it answers in every mode — the footer that carries the same fact exists only in `tui`. No rate is suggested. |
|
|
358
101
|
| `/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. |
|
|
102
|
+
| `/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
103
|
|
|
360
104
|
Tab completes the subcommands, extension names after `doctor`, and `refresh`;
|
|
361
|
-
`/bytefly settings`, `/bytefly skills`,
|
|
105
|
+
`/bytefly settings`, `/bytefly skills`, `/bytefly prices`, `/bytefly update`, and
|
|
106
|
+
`/bytefly upgrade` take no name.
|
|
362
107
|
|
|
363
108
|
## Behaviour by mode
|
|
364
109
|
|
|
@@ -387,20 +132,20 @@ print/JSON/RPC run gets an OS-level notification or none.
|
|
|
387
132
|
Two things are JSON: the transcript rail's glyph (`chrome.rail`, default `╎`,
|
|
388
133
|
read at `session_start`/`session_tree`) and this extension's three config
|
|
389
134
|
sections — `price`, `notify`, and `doctor`. Everything else about the look is
|
|
390
|
-
tuned in code: the header in [`header/config.ts`](
|
|
135
|
+
tuned in code: the header in [`header/config.ts`](../../extensions/bytefly/header/config.ts) (mark and
|
|
391
136
|
identity tokens, tagline, grouped help), the footer in
|
|
392
|
-
[`footer/config.ts`](
|
|
137
|
+
[`footer/config.ts`](../../extensions/bytefly/footer/config.ts) (thresholds, gauge glyphs and widths,
|
|
393
138
|
separators, icons, status keys), and the turn separator in
|
|
394
|
-
[`separator/config.ts`](
|
|
139
|
+
[`separator/config.ts`](../../extensions/bytefly/separator/config.ts) (glyph, label prefix, padding,
|
|
395
140
|
minimum duration, outcome wording, colors).
|
|
396
141
|
|
|
397
142
|
Every key of every section is listed with its type, default, and bounds in
|
|
398
|
-
[`docs/configuration.md`](
|
|
143
|
+
[`docs/configuration.md`](../configuration.md); this section
|
|
399
144
|
covers what that table cannot — when each section is read, and what the cost
|
|
400
145
|
does when no rate matches.
|
|
401
146
|
|
|
402
147
|
`bytefly.json` is one shared document with a top-level section per extension (see
|
|
403
|
-
[Configuration](
|
|
148
|
+
[Configuration](../configuration.md)). It is read from the global
|
|
404
149
|
document, then `<cwd>/.pi/bytefly.json`, project winning. The old per-extension
|
|
405
150
|
files (`document.json`, `jobs.json`, …) are no longer read; `bun run config:migrate`
|
|
406
151
|
moves them into the shared document.
|
|
@@ -449,7 +194,7 @@ catch-all prices everything).
|
|
|
449
194
|
| Section | Read at | Applies to |
|
|
450
195
|
|---|---|---|
|
|
451
196
|
| `chrome` | `session_start`, `session_tree` | the rail glyph |
|
|
452
|
-
| `price` | the footer install (`session_start`, `session_tree`) | the cost total |
|
|
197
|
+
| `price` | the footer install (`session_start`, `session_tree`) | the cost total and the budget ceiling beside it |
|
|
453
198
|
| `notify` | `session_start` | which events are announced, and how |
|
|
454
199
|
| `doctor` | `session_start` | the proactive check |
|
|
455
200
|
|
|
@@ -477,13 +222,166 @@ the model reads the same sentence.
|
|
|
477
222
|
- The extension screen registers no model-facing tool; toggling writes only
|
|
478
223
|
through Pi's `settings.json`, and `run_doctor` is read-only.
|
|
479
224
|
|
|
225
|
+
## Startup header
|
|
226
|
+
|
|
227
|
+
A nameplate: a two-tone half-block mark from the active theme's `accent` /
|
|
228
|
+
`warn` roles, the agent identity (`Pi`, bold, and its version), the chrome
|
|
229
|
+
identity (`enhanced by bytefly` and the package version), a signature rule whose
|
|
230
|
+
`accent` lead sits under the mark, and a grouped help block. The help keys
|
|
231
|
+
resolve live from Pi's keybindings, so a rebound key shows the user's chord; the
|
|
232
|
+
identity and help text are `meta` / `faint` so the mark keeps the eye. It opens
|
|
233
|
+
with a blank row, so the nameplate clears the top edge. It is installed only in
|
|
234
|
+
interactive (`tui`) sessions when Pi's `quietStartup` is `true` — the Settings
|
|
235
|
+
row **Startup screen** — and `false`, `"header"`, and unset leave Pi's
|
|
236
|
+
built-in header in place; on terminals that cannot render half blocks the mark
|
|
237
|
+
falls back to a two-tone `Pi` wordmark.
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
█▀█ Pi v1.2.0
|
|
241
|
+
█▀ █ enhanced by bytefly v0.8.1
|
|
242
|
+
─────────────────────────────────────────────────
|
|
243
|
+
escape to interrupt · ctrl+c to clear · ctrl+d to exit (empty)
|
|
244
|
+
ctrl+o to expand tools · ctrl+t to expand thinking · ctrl+l to select model
|
|
245
|
+
/ commands · ! bash · !! bash (no context) · /bytefly extensions
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
As the terminal narrows, the identity sheds the chrome marker, then the chrome
|
|
249
|
+
version, then the chrome line, then Pi's marker with the agent name, and the help
|
|
250
|
+
rows drop whole keys, so nothing wraps or clips mid-word. Height sheds the same way: at 28 rows
|
|
251
|
+
all three help groups print, below 28 the middle group (the expand and model
|
|
252
|
+
chords) goes first, below 22 only the `/` commands row survives, and below 16 the
|
|
253
|
+
help block and the leading blank row go, leaving the nameplate and its rule. An
|
|
254
|
+
unknown height keeps the full header. The nameplate sits on the transcript
|
|
255
|
+
margin, which follows Pi's `outputPad` (the value the tool frame and the notice
|
|
256
|
+
use too), and the help hangs one body indent inside it. The mark, tokens,
|
|
257
|
+
identity, and grouped help are tuned in
|
|
258
|
+
[`header/config.ts`](../../extensions/bytefly/header/config.ts).
|
|
259
|
+
|
|
260
|
+
## Content and colors
|
|
261
|
+
|
|
262
|
+
Two lines, each with a left and right zone:
|
|
263
|
+
|
|
264
|
+
- **Line 1 — identity:** `pwd` and the session name on the left; on the right the
|
|
265
|
+
alert, then the mode chips (`≡ plan`), then `⎇ branch · ⑂ worktree`, then the
|
|
266
|
+
ports (`⊞ 5043 · ◉ 4909`) while a page is being served. The board page and the
|
|
267
|
+
file browser each publish one status key, and the bar reads both as a single
|
|
268
|
+
segment, so they share a weight, a position, and a floor.
|
|
269
|
+
- **Line 2 — resources:** the context gauge and usage meters on the left, the
|
|
270
|
+
child-run roll-up (`↳ 3 · ¥0.12`, present only once a subagent has finished),
|
|
271
|
+
and the model and thinking level on the right. The gauge is anchored at column
|
|
272
|
+
0, so `%` is always in the same place.
|
|
273
|
+
The roll-up is its own number, never folded into the session's cost: a subagent
|
|
274
|
+
runs in its own process, and the footer prices those runs with the same rate
|
|
275
|
+
table and currency as the session so a currency change moves both. It covers
|
|
276
|
+
the last 500 child runs of the current process, and starts from zero after
|
|
277
|
+
`/resume` (the events are not session entries).
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
~/repo/my-pi-agent ≡ plan · ⎇ main · ⑂ smoke
|
|
281
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↳ 2 · ¥0.06 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
(The examples show the default `¥` symbol. A model that neither `rates` nor the
|
|
285
|
+
built-in table covers contributes nothing in `CNY` mode, so the bar shows no
|
|
286
|
+
figure rather than a guessed one; `USD` mode adds Pi's recorded dollars for that
|
|
287
|
+
record instead — see [Cost calculation](#cost-calculation).)
|
|
288
|
+
|
|
289
|
+
With no plan mode the mode slot is simply absent:
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
293
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
While a page is served, its port joins the run beside the worktree — both pages as
|
|
297
|
+
one cluster, in a fixed order, so the pair reads as a pair:
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
~/repo/my-pi-agent ⎇ main · ⊞ 5043 · ◉ 4909
|
|
301
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
As the terminal narrows, segments shrink and drop by priority rather than
|
|
305
|
+
clipping. The branch keeps its name and is dropped when the name no longer
|
|
306
|
+
fits, rather than collapsing to a bare glyph:
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
~/repo/my-pi-agent ≡ plan · ⎇ main · ⑂
|
|
310
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 opus-4.5 · high
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
~/my-pi-agent ⎇ main
|
|
315
|
+
▰▰▰▰▰▰▱▱▱▱ 62% opus-4.5
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
A port is dropped before the pages it names are: the cluster compacts to
|
|
319
|
+
`⊞ ◉` once the digits no longer fit, so the narrowest bar that fits the location
|
|
320
|
+
chips still says a page is up.
|
|
321
|
+
|
|
322
|
+
```
|
|
323
|
+
~/repo/my-pi-agent ⎇ main · ⊞ ◉
|
|
324
|
+
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31 opus-4.5 · high
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
With a named session, the name follows the path and truncates before it drops:
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
~/repo/project · [feature-refac…] ⎇ main
|
|
331
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 opus-4.5 · high
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
Zero-value meters are omitted, so a fresh session shows only `?/window` instead
|
|
335
|
+
of a row of `¥0.00 · ↑0 ↓0 · R0 W0`. Unknown context usage shows a muted `?`
|
|
336
|
+
with no gauge (known `0%` still draws the empty gauge), so unknown and zero stay
|
|
337
|
+
distinct. Cost keeps the configured precision — the segment drops rather than
|
|
338
|
+
rounding to a misleading `¥0.3` — and a positive amount below one minor unit
|
|
339
|
+
shows as `¥<0.01` rather than `¥0.00`.
|
|
340
|
+
|
|
341
|
+
Each segment reads a theme role and carries its own drop order:
|
|
342
|
+
|
|
343
|
+
| Segment | Line / zone | Color | Drops |
|
|
344
|
+
|---|---|---|---|
|
|
345
|
+
| pwd | 1 left | dim | last |
|
|
346
|
+
| session | 1 left | muted, bracketed | after worktree |
|
|
347
|
+
| branch | 1 right | muted (warning when detached) | last |
|
|
348
|
+
| worktree | 1 right | success | first |
|
|
349
|
+
| ports `⊞ 5043 · ◉ 4909` | 1 right | success glyphs + accent ports | first, in one step |
|
|
350
|
+
| context gauge + `%` | 2 left | muted ≤70 · warning 71–90 · error >90 | never |
|
|
351
|
+
| `/window` | 2 left | dim | before cost |
|
|
352
|
+
| cost | 2 left | muted | after tokens |
|
|
353
|
+
| tokens `↑in ↓out` | 2 left | dim | after cache |
|
|
354
|
+
| cache `R… CH …%` | 2 left | dim | first |
|
|
355
|
+
| statuses | 1 right | as emitted by each extension | before branch |
|
|
356
|
+
| model | 2 right | accent | never |
|
|
357
|
+
| thinking level | 2 right | thinking token | before cost |
|
|
358
|
+
|
|
359
|
+
The worktree status is read from the `worktree` status key, so the
|
|
360
|
+
[worktree](./worktree.md) extension and the bar agree. The ports are the `board`
|
|
361
|
+
and `browse` status keys, published by [board](./board.md) and
|
|
362
|
+
[file-browse](./file-browse.md) while their pages are served. One segment reads
|
|
363
|
+
both, in a fixed order (board, then browse), each a two-tone `<glyph> <port>`
|
|
364
|
+
with a green glyph and an accent port. That is one fact — "a page is up on this
|
|
365
|
+
port" — so it gets one weight and one floor: the pair compacts from
|
|
366
|
+
`⊞ 5043 · ◉ 4909` to `⊞ 5043 ◉ 4909` to `⊞ ◉`, and it drops as a unit, where
|
|
367
|
+
separate chips once let the board port outlive the browse one by four columns
|
|
368
|
+
for no reason a reader could see.
|
|
369
|
+
|
|
370
|
+
The mode slot holds everything else an extension publishes: a plan chip, a
|
|
371
|
+
job count, a rewind timeline, the `✆` bridge, and an alert's front position. A
|
|
372
|
+
plan chip's trailing plan file name is dropped, so the slot reads `≡ plan` even
|
|
373
|
+
though the built-in footer keeps the name, and an alert (a failed job) sorts to
|
|
374
|
+
the front of it. It keeps each extension's own colour when it compacts, and it is
|
|
375
|
+
droppable: a tight bar drops the slot rather than truncating the model, which
|
|
376
|
+
sits at the end of the line.
|
|
377
|
+
|
|
480
378
|
## Cost calculation
|
|
481
379
|
|
|
482
380
|
Pi prices every model call from its bundled catalog in USD, and the provider API
|
|
483
381
|
never returns a price. The footer can total that catalog directly, or replace
|
|
484
382
|
it with its own rates for the models they match:
|
|
485
383
|
|
|
486
|
-
- **Which built-in rates.** [`footer/price/config.ts`](
|
|
384
|
+
- **Which built-in rates.** [`footer/price/config.ts`](../../extensions/bytefly/footer/price/config.ts) ships DeepSeek's published
|
|
487
385
|
yuan prices for `CNY` and its published dollar prices for `USD`, per model, with
|
|
488
386
|
the peak schedule that doubles the price during peak hours
|
|
489
387
|
([DeepSeek's pricing page](https://api-docs.deepseek.com/quick_start/pricing)).
|
|
@@ -514,41 +412,79 @@ it with its own rates for the models they match:
|
|
|
514
412
|
leaves out; `USD` adds Pi's recorded dollar amount for that record, because
|
|
515
413
|
that number is already dollars and already per model.
|
|
516
414
|
|
|
415
|
+
DeepSeek needs no config file at all: the bar prices it from the published yuan
|
|
416
|
+
rates and peak tariff built into [`footer/price/config.ts`](../../extensions/bytefly/footer/price/config.ts).
|
|
417
|
+
Those tables record the day they were last checked against the published tariff,
|
|
418
|
+
and `doctor` reports how old that is, so a re-pricing shows up as a warning instead
|
|
419
|
+
of a quietly wrong total. A `bytefly.json` can switch to the published dollar table,
|
|
420
|
+
add models of your own, or replace a built-in entry:
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
~/repo/project ⎇ main
|
|
424
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥2.50 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`price.budget` puts a threshold under that total, in the same currency: when the
|
|
428
|
+
session's cost reaches it, one `bytefly · Session budget reached` notice names
|
|
429
|
+
what was spent against the budget, and one OS notification follows when notify
|
|
430
|
+
is enabled. It is an alert, not a limit — no turn is blocked or aborted — and it
|
|
431
|
+
fires once per session, on the turn where the crossing becomes final (the run
|
|
432
|
+
settling), because a warning per turn after that is noise. `0`, the default,
|
|
433
|
+
turns it off. The check reads the total the footer already priced, and the
|
|
434
|
+
footer exists only in `tui` sessions, so a print or JSON run has no budget
|
|
435
|
+
alert; the footer's own numbers are visible in every interactive session.
|
|
436
|
+
|
|
437
|
+
A record nothing prices contributes nothing to the total. `CNY` has no fallback at
|
|
438
|
+
all; `USD` falls back to Pi's recorded amount, which is `0` for a model its catalog
|
|
439
|
+
does not know either. So "unpriced" means the same thing in both modes — no
|
|
440
|
+
`price.rates` key matched **and** nothing else priced it — and it is counted by
|
|
441
|
+
*model*, because a count says the total is short while a key says what to do:
|
|
442
|
+
|
|
443
|
+
- The footer's cost segment marks it: `¥1.23 · 2 unpriced`, dropping to the count
|
|
444
|
+
alone on a narrow bar. A session where nothing could be priced shows `2 unpriced`
|
|
445
|
+
beside no price at all, where it used to show nothing.
|
|
446
|
+
- `/bytefly prices` lists them — the key, the records behind it, and the line saying
|
|
447
|
+
where the keys go. It prices the session when asked, so it works in every mode,
|
|
448
|
+
including the ones with no footer.
|
|
449
|
+
- One `bytefly · Records with no rate` notice fires per session, on the run that
|
|
450
|
+
settles, naming up to three keys. The two fixes it offers are both honest: switch
|
|
451
|
+
`price.currency.code` to `USD` (Pi's catalog is per model, tiers included) or add
|
|
452
|
+
`price.rates` entries for those keys.
|
|
453
|
+
|
|
454
|
+
The key is the `price.rates` vocabulary, so it is copy-pasteable: `provider/model`,
|
|
455
|
+
`*` for a side the history does not name, and a model id containing a slash kept
|
|
456
|
+
whole (`openrouter/anthropic/claude-fable-5`). A genuinely free model — a local one
|
|
457
|
+
whose recorded cost is `0` — is listed too; adding its key costs nothing.
|
|
458
|
+
|
|
517
459
|
For example, DeepSeek flash at `¥2` in and `¥8` out per million, with the
|
|
518
460
|
published peak windows and `offPeakMultiplier: 0.5`, prices a 1M-in + 1M-out
|
|
519
461
|
turn at `¥10.00` at peak and `¥5.00` off-peak. That example is worked end to end
|
|
520
|
-
in [`footer/footer.test.ts`](
|
|
462
|
+
in [`footer/footer.test.ts`](../../extensions/bytefly/footer/footer.test.ts), which also prices the built-in
|
|
521
463
|
table with no config file at all.
|
|
522
464
|
|
|
523
|
-
##
|
|
465
|
+
## The user-message nameplate
|
|
524
466
|
|
|
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 |
|
|
467
|
+
Every user message opens with a two-row `You` nameplate — the label over a rule
|
|
468
|
+
that spans the width — above the message:
|
|
540
469
|
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
the
|
|
470
|
+
```
|
|
471
|
+
You
|
|
472
|
+
────────────────────────────────────
|
|
473
|
+
|
|
474
|
+
the message the user typed
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
It is always on in interactive sessions and has no config file. Pi renders a
|
|
478
|
+
user message as Markdown and owns its colors, so bytefly's only lever is a
|
|
479
|
+
`registerMarkdownTransformer`: the nameplate is a single level-2 heading whose
|
|
480
|
+
text is padded so the rule wraps onto the second row, and both rows carry the
|
|
481
|
+
accent because the themes point `mdHeading` at it. The block carries no fill —
|
|
482
|
+
the shipped themes set `userMessageBg` to the terminal default, so it reads like
|
|
483
|
+
the tool blocks. The nameplate is separated from the message by a blank line, so
|
|
484
|
+
the message's own Markdown (a fence, a list, a second paragraph) parses exactly
|
|
485
|
+
as it would without it, and a soft wrap of one long line stays at the margin
|
|
486
|
+
because the renderer wraps it, not bytefly. The label and the rule are tuned
|
|
487
|
+
in [`message/config.ts`](../../extensions/bytefly/message/config.ts).
|
|
552
488
|
|
|
553
489
|
## Turn separator
|
|
554
490
|
|
|
@@ -589,43 +525,258 @@ and outcome as the width allows.
|
|
|
589
525
|
rule; disable the whole extension with `bytefly` instead.
|
|
590
526
|
- There is no runtime command; the glyph, label prefix, padding, colors, and
|
|
591
527
|
minimum duration are tuned in
|
|
592
|
-
[`separator/config.ts`](
|
|
528
|
+
[`separator/config.ts`](../../extensions/bytefly/separator/config.ts).
|
|
529
|
+
|
|
530
|
+
## Notices
|
|
531
|
+
|
|
532
|
+
Any extension in the package can post a transcript notice under the shared
|
|
533
|
+
`my-pi-agent/notice` type; bytefly draws it at the transcript's margin — a
|
|
534
|
+
`source · title` headline at the margin, then rail-led rows, each with its own
|
|
535
|
+
severity glyph:
|
|
536
|
+
|
|
537
|
+
```
|
|
538
|
+
job · 2 background jobs finished
|
|
539
|
+
╎ ✓ j1 build · exit 0
|
|
540
|
+
╎ ✕ j2 test · exit 1
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
The rail is painted by the notice's worst severity, so a failure reads red at the
|
|
544
|
+
edge like an errored tool result, and the headline's title takes the notice's own
|
|
545
|
+
severity — a warning reads yellow where its sentence is, while an `info` or `ok`
|
|
546
|
+
notice stays body text. A row's label stays body text too: its severity is the
|
|
547
|
+
glyph it hangs on, so one failing row never tints the rest of the list.
|
|
548
|
+
|
|
549
|
+
`job` and `watch` post one when a background job finishes or a watched line
|
|
550
|
+
matches, so the report the model reads is visible too. `doctor` posts one when a
|
|
551
|
+
hard requirement is missing at session start, with a row per finding and the
|
|
552
|
+
command that fixes it:
|
|
553
|
+
|
|
554
|
+
```
|
|
555
|
+
doctor · 1 missing prerequisite
|
|
556
|
+
╎ ✕ worktree (git) · install git and make sure it is on PATH
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
Only a missing *hard* requirement posts a notice at session start; everything
|
|
560
|
+
else waits in the report.
|
|
561
|
+
|
|
562
|
+
The type and the `NoticeDetails` shape are the shared contract in
|
|
563
|
+
[`lib/notice.ts`](../../lib/notice.ts), and the severity glyphs and item cap
|
|
564
|
+
are tuned in [`notice/config.ts`](../../extensions/bytefly/notice/config.ts). Every field is sanitized
|
|
565
|
+
and clipped at the boundary, and a message without `details` keeps Pi's default
|
|
566
|
+
custom-message box.
|
|
567
|
+
|
|
568
|
+
## Compaction
|
|
569
|
+
|
|
570
|
+
`/compact` is Pi's own surface: its summary block is a built-in message
|
|
571
|
+
component, so bytefly cannot replace, hide, or shorten it. The shipped themes
|
|
572
|
+
only remove its fill — `customMessageBg` is the terminal default — and paint the
|
|
573
|
+
`[compaction]` label in the accent, so the block sits on the canvas like the
|
|
574
|
+
rest of the transcript. Pi's branch summaries and skill invocations share the
|
|
575
|
+
same tokens.
|
|
576
|
+
|
|
577
|
+
<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%">
|
|
578
|
+
|
|
579
|
+
## Tool blocks
|
|
580
|
+
|
|
581
|
+
Every tool block leads with the tool's own call line as the headline — the tool
|
|
582
|
+
name in the theme's tool-title colour — and its result body sits two columns in
|
|
583
|
+
directly beneath it, led by the transcript rail, instead of Pi's filled status
|
|
584
|
+
background:
|
|
585
|
+
|
|
586
|
+
```
|
|
587
|
+
read src/app.ts
|
|
588
|
+
╎ const answer = 42;
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
The two tools that mutate a file, `edit` and `write`, carry their result on the
|
|
592
|
+
call body — the edit diff, the written file content — so that body is railed
|
|
593
|
+
like any other result. There is no status band: the diff's own red/green line
|
|
594
|
+
colours, with the changed words in reverse video, and the `edit` / `write`
|
|
595
|
+
headline are what mark a file change.
|
|
596
|
+
|
|
597
|
+
A `registerToolRenderer` resolver switches the row to `renderShell: "self"`,
|
|
598
|
+
leaves the call's own first line as the headline, and indents the rest of the
|
|
599
|
+
call and the whole result under it. A shell call's `$` / `>` prompt becomes the
|
|
600
|
+
tool name and the command is repainted in the body colour, and a primary subject
|
|
601
|
+
(a path, URL, query, pattern) is demoted to the body colour too, so the name is
|
|
602
|
+
the call line's only accent (`bash bun run check`, `read src/app.ts`). The
|
|
603
|
+
tool's own
|
|
604
|
+
`renderCall`/`renderResult` are passed through, so syntax highlighting, diffs,
|
|
605
|
+
previews, and truncation notices are unchanged — only the frame is bytefly's.
|
|
606
|
+
The body carries the transcript rail, painted by status (a running result takes
|
|
607
|
+
the accent, a failure red, a finished one neutral) and drawn with the glyph from
|
|
608
|
+
the `chrome.rail` setting. A result frame is always railed; a call frame is railed
|
|
609
|
+
only for `edit` and `write`, whose call body carries the result — every other
|
|
610
|
+
call's headline and continuation lines stay plain-indented. Package renderers
|
|
611
|
+
clip a call to one physical line (middle clip for a path or URL), so it cannot
|
|
612
|
+
leak into the body column; Pi's own renderers still wrap, and the frame keeps a
|
|
613
|
+
wrapped continuation unrailed and loses the accent there too, with the rail
|
|
614
|
+
beginning at the result underneath. A rejected call renders as one sanitized
|
|
615
|
+
`error` line in the error role; a running tool shows a live elapsed label, and a
|
|
616
|
+
finished long call appends its duration. A tool with
|
|
617
|
+
no renderer of its own is framed around a generic call/result fallback, whose
|
|
618
|
+
call line reads like a built-in — the leading string argument bare, the rest as
|
|
619
|
+
trailing options (`open_path src/app.ts`) — rather than dumping raw `key=value`
|
|
620
|
+
pairs. A tool that draws its own shell (`edit`) is framed too:
|
|
621
|
+
`renderShell: "self"` only tells Pi not to draw its box around the renderer, so
|
|
622
|
+
its diff would otherwise sit at the wrong indent; the frame drops the blank
|
|
623
|
+
edges its own `Box` pads itself with, and hands it a theme whose `bg` is inert so
|
|
624
|
+
it never paints a band the rest of the transcript does not have.
|
|
625
|
+
|
|
626
|
+
The call line is one colour grammar, shared with Pi's built-ins: the tool name is
|
|
627
|
+
`toolTitle` and bold and is the line's only accent; a primary subject (a query, a
|
|
628
|
+
URL, a path, a status) reads in the body role (`label`), counts and summaries are
|
|
629
|
+
`muted`, trailing options are `dim`, and the result body is `toolOutput`. The
|
|
630
|
+
shipped themes point `toolTitle` at the accent and `label` at the body colour, so
|
|
631
|
+
the name is the call line's one accent and the subject follows as body text; a
|
|
632
|
+
theme that maps `toolTitle` elsewhere is respected rather than overridden.
|
|
633
|
+
|
|
634
|
+
## The working line
|
|
635
|
+
|
|
636
|
+
Pi's working row shows a static `Working`, so a long run reads the same as a
|
|
637
|
+
short one. While the row is up, bytefly advances its message once a second and
|
|
638
|
+
hands it back to Pi when the row comes down. Before the first tool starts it is
|
|
639
|
+
a count:
|
|
640
|
+
|
|
641
|
+
```
|
|
642
|
+
Working… 12s
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
Once a top-level tool starts, the row becomes a live run line: the tool, how
|
|
646
|
+
many top-level tools this run has started, and the elapsed time.
|
|
647
|
+
|
|
648
|
+
```
|
|
649
|
+
edit · 3 tools · 12s
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
A nested tool call (one carrying `parentToolCallId`, such as a codemode script's
|
|
653
|
+
inner call) neither counts nor takes over the line, so the number matches the
|
|
654
|
+
tool blocks in the transcript. The line keeps the last tool name while the
|
|
655
|
+
model streams after it, and a tool event repaints the row immediately instead
|
|
656
|
+
of waiting for the next tick. The line covers the whole run, tool calls
|
|
657
|
+
included. It is tied to the row's visibility: it starts on `turn_start`, stops
|
|
658
|
+
on `agent_end`, and is reset on `session_shutdown`; turns inside one run do not
|
|
659
|
+
restart it, and a retry starts a new run. The words and the interval are tuned
|
|
660
|
+
in [`working/config.ts`](../../extensions/bytefly/working/config.ts).
|
|
593
661
|
|
|
594
662
|
## The control center
|
|
595
663
|
|
|
596
|
-
<img src="../../assets/bytefly.png" alt="The /bytefly control center:
|
|
664
|
+
<img src="../../assets/screens/bytefly.png" alt="The /bytefly control center at 120 columns: a `Bytefly` rule with `1 missing` at its right edge, the `Extensions 9 · Skills 0 · Settings 12` tabs with `writes Global` at the right, one name-first row per extension with its checkbox and verdict, and the focused extension's block beside the list — its findings and their fix, Path, Source, State, and Health" width="100%">
|
|
597
665
|
|
|
598
666
|
`/bytefly [extension] [refresh]` opens the control center on **Extensions**: a
|
|
599
|
-
keyboard-driven dock
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
enable checkbox and label, then one verdict — `off` when the row is switched off
|
|
606
|
-
in settings, `env disabled` when `PI_DISABLED_EXTENSIONS` excludes it, otherwise
|
|
607
|
-
the doctor's worst-severity glyph and summary. The screen is drawn from the
|
|
608
|
-
design system: a label-first `Bytefly ────` title rule,
|
|
609
|
-
the `Extensions · Skills · Settings` section bar beside the section's counts, one
|
|
610
|
-
row grammar (`❯ ◼ name … summary`), the shared `◼` / `◻` checkbox, and the closing
|
|
611
|
-
rule under the key hints that Pi's own list screens draw.
|
|
612
|
-
`/bytefly doctor [extension] [refresh]` selects the doctor report, the same text
|
|
613
|
-
the `run_doctor` tool returns; in `tui` it opens the same screen. `[extension]`
|
|
614
|
-
narrows the Extensions section to one extension and `refresh` forces the first
|
|
615
|
-
probe. Tab completes the subcommands, extension names after `doctor`, and
|
|
616
|
-
`refresh`; `/bytefly settings` and `/bytefly skills` take no name.
|
|
667
|
+
keyboard-driven dock of every resource Pi resolves for the session, so the list
|
|
668
|
+
matches what actually loads. `/bytefly skills` and `/bytefly settings` open the
|
|
669
|
+
other two sections directly, and `←`/`→` (or `h`/`l`, or `Tab`) change section,
|
|
670
|
+
wrapping at the ends because the tabs read as a ring. `/bytefly <extension>`
|
|
671
|
+
narrows the list to one extension, and `refresh` forces the first probe. One
|
|
672
|
+
frame draws all three sections.
|
|
617
673
|
|
|
618
674
|
The screen opens on the findings the session already has, and the Extensions
|
|
619
675
|
section probes once on its first view (the hint shows `refreshing…` while it
|
|
620
676
|
runs). `/bytefly settings` therefore never waits for a probe, and a failed probe
|
|
621
677
|
is a notice with the screen still open rather than a refused command. A refusal
|
|
622
|
-
or a failed write appears in the screen's own hint row
|
|
623
|
-
aside
|
|
678
|
+
or a failed write appears in the screen's own hint row — the key hints step
|
|
679
|
+
aside — and clears on the next key, so nothing is written behind the screen.
|
|
624
680
|
|
|
625
681
|
The screen reuses Pi's own settings and package resolution (`SettingsManager`
|
|
626
682
|
plus `DefaultPackageManager` with `onMissing: "skip"`), so opening it never
|
|
627
683
|
installs or fetches a package.
|
|
628
684
|
|
|
685
|
+
**One frame.** The `Bytefly ────` header rule carries the screen's attention at
|
|
686
|
+
its right edge — `1 missing` or `2 degraded` in the severity's own colour, else
|
|
687
|
+
`2 off`, else `all clear`, with `unsaved changes` after it while a write is
|
|
688
|
+
pending. The tab row below names every section with the rows it holds,
|
|
689
|
+
`Extensions 9 · Skills 0 · Settings 12`, the active tab in the accent and the
|
|
690
|
+
counts faint, then any filter chips (`/git`, `needs attention`, `changed only`),
|
|
691
|
+
with `writes Global` (or `writes Project`) at the right edge. The scope is a word
|
|
692
|
+
there because no count line has to carry it any more: the counts are on the tabs,
|
|
693
|
+
the problems are in the header, and the scope is at the right.
|
|
694
|
+
|
|
695
|
+
The body is padded to the tallest section's row count, group headings counted, so
|
|
696
|
+
all three sections draw the same height and the dock does not resize when the
|
|
697
|
+
tabs change. A shorter section pads its last rows with blanks; a longer one
|
|
698
|
+
scrolls inside the same height and puts `showing 3–14 of 19` on its last body
|
|
699
|
+
row. The height is measured from both resource lists and the visible scope's
|
|
700
|
+
settings rows, so changing tab does not resize the dock: only a resize of the
|
|
701
|
+
terminal moves the hint row, or the Project scope's one-line note on a terminal
|
|
702
|
+
too short to hold both.
|
|
703
|
+
|
|
704
|
+
**Two panes.** At 96 columns and wider the focused row's block sits in a side
|
|
705
|
+
column after a `╎` divider: the row's name and verdict; the doctor's findings,
|
|
706
|
+
under a `── findings ──` rule and each with its fix; `Path`, `Source`, and
|
|
707
|
+
`State` for a resolved resource; `Health` when the row has a report; and
|
|
708
|
+
`Saved · reload to apply` once something is pending. Below 96 columns the same
|
|
709
|
+
block is drawn under the list in three rows, clipped, ending with
|
|
710
|
+
`… N more lines` when it has more to say; it leaves out what the row above
|
|
711
|
+
already says — the name and verdict on a resource row, the label and value on a
|
|
712
|
+
settings row, and the path when there are findings to show instead.
|
|
713
|
+
|
|
714
|
+
The picture above is 120 columns wide; the two frames below are the same screen
|
|
715
|
+
at 100 and 80.
|
|
716
|
+
|
|
717
|
+
```
|
|
718
|
+
Bytefly ────────────────────────────────────────────────────────────────────────────────── 1 missing
|
|
719
|
+
Extensions 9 · Skills 0 · Settings 12 writes Global
|
|
720
|
+
|
|
721
|
+
npm:pkg (user) (9) ╎ worktree 1 missing
|
|
722
|
+
◼ file-read ╎ ── findings ────────────────────────────
|
|
723
|
+
◼ job ╎ git: not found on PATH — worktree
|
|
724
|
+
◼ memory ╎ isolation
|
|
725
|
+
◼ plan ╎ → install git and make sure it is on
|
|
726
|
+
◼ subagent ╎ PATH (https://git-scm.com/downloads).
|
|
727
|
+
◼ todo ╎ symlink: the host cannot create symlinks
|
|
728
|
+
◻ ∅ web-access off ╎ → copy the included files by hand.
|
|
729
|
+
◻ ∅ wechat off ╎ Path /pkg/extensions/worktree/ind…
|
|
730
|
+
❯ ◼ ✕ worktree 1 missing ╎ Source npm:pkg (user)
|
|
731
|
+
Not resolved (1) ╎ State enabled
|
|
732
|
+
bytefly ok ╎ Health 1 missing
|
|
733
|
+
╎
|
|
734
|
+
╎
|
|
735
|
+
╎
|
|
736
|
+
╎
|
|
737
|
+
|
|
738
|
+
Esc close · ←/→ section · Space toggle · Enter detail · / filter · ? keys · r refresh · s scope
|
|
739
|
+
────────────────────────────────────────────────────────────────────────────────────────────────────
|
|
740
|
+
```
|
|
741
|
+
|
|
742
|
+
```
|
|
743
|
+
Bytefly ────────────────────────────────────────────────────────────── 1 missing
|
|
744
|
+
Extensions 9 · Skills 0 · Settings 12 writes Global
|
|
745
|
+
|
|
746
|
+
npm:pkg (user) (9)
|
|
747
|
+
◼ file-read
|
|
748
|
+
◼ job
|
|
749
|
+
◼ memory
|
|
750
|
+
◼ plan
|
|
751
|
+
◼ subagent
|
|
752
|
+
◼ todo
|
|
753
|
+
◻ ∅ web-access off
|
|
754
|
+
◻ ∅ wechat off
|
|
755
|
+
❯ ◼ ✕ worktree 1 missing
|
|
756
|
+
Not resolved (1)
|
|
757
|
+
bytefly ok
|
|
758
|
+
|
|
759
|
+
git: not found on PATH — worktree isolation
|
|
760
|
+
→ install git and make sure it is on PATH (https://git-scm.com/downloads).
|
|
761
|
+
… 2 more lines
|
|
762
|
+
|
|
763
|
+
Esc close · ←/→ section · Space toggle · Enter detail · / filter · ? keys
|
|
764
|
+
────────────────────────────────────────────────────────────────────────────────
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
At 80 columns the block's three rows clip to the first finding and its fix and
|
|
768
|
+
say how many lines are left out, and the hint row has already shed `r refresh`
|
|
769
|
+
and `s scope` from its right edge.
|
|
770
|
+
|
|
771
|
+
**Rows.** A row is named for the resource, not for its file: `worktree`, not
|
|
772
|
+
`worktree/index.ts`. The picker's `folder/file.ts` label survives only where two
|
|
773
|
+
resources share a directory name, because the two rows would otherwise read
|
|
774
|
+
alike. What is left is one checkbox, one status glyph and one verdict word —
|
|
775
|
+
`off`, `1 missing`, `2 degraded`, `env disabled`, `not loaded` for a skill Pi
|
|
776
|
+
refused, `hidden` for one its frontmatter keeps from the model — and a clean row
|
|
777
|
+
carries no glyph and no word at all, so the column reads as one shape and the eye
|
|
778
|
+
finds the rows that need it.
|
|
779
|
+
|
|
629
780
|
- Lists every resolved extension, grouped by source (each package, user
|
|
630
781
|
settings, project settings), sorted packages-first and then by display name.
|
|
631
782
|
- Omits `bytefly`'s own entrypoint from the picker groups, so the tool that
|
|
@@ -636,11 +787,10 @@ installs or fetches a package.
|
|
|
636
787
|
glyph (`!` degraded, `✕` missing) and its summary. A row that is `◻` reads
|
|
637
788
|
`off` instead, because it will not load; a row the session's
|
|
638
789
|
`PI_DISABLED_EXTENSIONS` excludes reads `env disabled`, so the two axes cannot
|
|
639
|
-
contradict each other.
|
|
640
|
-
nothing to report — a clean report or none at all — leaves the glyph column
|
|
790
|
+
contradict each other. A row with nothing to report leaves the glyph column
|
|
641
791
|
blank and says `ok` in words when a report exists.
|
|
642
792
|
- Toggles the focused extension with `Space`, writing `+pattern` / `-pattern`
|
|
643
|
-
into `extensions` (and package filter objects) in the
|
|
793
|
+
into `extensions` (and package filter objects) in the write scope. A row in
|
|
644
794
|
the trailing `Not resolved` group has no pattern to write, so `Space` says so
|
|
645
795
|
instead of doing nothing.
|
|
646
796
|
- Clears the focused extension's project override with `x` in Project scope: the
|
|
@@ -649,30 +799,37 @@ installs or fetches a package.
|
|
|
649
799
|
created), and the row returns to its inherited state. A row with no override
|
|
650
800
|
says so instead of writing, and Global scope does not offer the key — the
|
|
651
801
|
personal file is the base layer.
|
|
652
|
-
- Switches the write scope with `Tab`: **Global** (personal `settings.json`) or
|
|
653
|
-
**Project** (`.pi/settings.json`, only when the project is trusted; an
|
|
654
|
-
untrusted project refuses with a notice).
|
|
655
802
|
- Expands or collapses the focused extension's findings with `Enter` — per row,
|
|
656
|
-
so another row stays as it was — and
|
|
657
|
-
height while
|
|
658
|
-
|
|
803
|
+
so another row stays as it was — and gives the block the screen's whole body
|
|
804
|
+
height while it is open, so its findings are not clipped to three rows.
|
|
805
|
+
- Re-probes with `r`; while a probe is in flight the hint shows `refreshing…` and
|
|
806
|
+
a second `r` is ignored, so probes cannot stack.
|
|
659
807
|
- Checks an `<extension>` name against the discovered set before probing, so a
|
|
660
808
|
typo fails immediately instead of waiting for every prerequisite check.
|
|
661
|
-
-
|
|
662
|
-
|
|
809
|
+
- Reloads with `R`, so a new selection takes effect without leaving the session.
|
|
810
|
+
|
|
811
|
+
**Filters.** `/` opens an editor seeded with the current query. The query applies
|
|
812
|
+
as it is typed — a filter that only took effect on `Enter` would make the reader
|
|
813
|
+
wait to see it work — and matches a row's name, path, and source (Settings: its
|
|
814
|
+
label, description, and value). `Esc` clears it rather than leaving a hidden
|
|
815
|
+
narrowing behind. `!` keeps only the rows worth acting on: a resource row that
|
|
816
|
+
needs attention, or on Settings a value that differs from its default. The chips
|
|
817
|
+
on the tab row say which is on, and an emptied section says
|
|
818
|
+
`Nothing matches the filter.`
|
|
663
819
|
|
|
664
820
|
**Skills.** The second section is the same list over Pi's skills: one row per
|
|
665
821
|
skill, grouped by source and sorted by name, labelled with the name its
|
|
666
822
|
`SKILL.md` declares (or the folder name when it declares none). `Space` writes
|
|
667
823
|
`+pattern` / `-pattern` into `skills` — or a package's `skills` filter — in the
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
`not loaded` with Pi's reason when the file was refused. The
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
824
|
+
write scope, and `x` behaves as it does for extensions. A row's verdict comes
|
|
825
|
+
from the skill's own file: `off` when it is disabled, `hidden` when frontmatter
|
|
826
|
+
sets `disable-model-invocation` so only `/skill:<name>` loads it, and
|
|
827
|
+
`not loaded` with Pi's reason when the file was refused. The block carries
|
|
828
|
+
`Path`, `Call` (`/skill:<name>`), `Model` when the skill is hidden from the
|
|
829
|
+
model, `Problem` when Pi refused the file, and the declared description — one
|
|
830
|
+
line until `Enter` expands it. There is nothing to probe, so `r` is not offered
|
|
831
|
+
here; the metadata is read once when the section first appears, so an edited
|
|
832
|
+
`SKILL.md` shows on the next open.
|
|
676
833
|
|
|
677
834
|
Themes and prompts have no section of their own, by decision rather than by
|
|
678
835
|
omission: a theme is one active selection — a scalar, global setting — and a
|
|
@@ -680,53 +837,40 @@ prompt template is a file Pi discovers from a directory, so neither is a scoped
|
|
|
680
837
|
enable list this screen's checkbox rows can write. Themes stay with `pi config`;
|
|
681
838
|
`ROADMAP.md` carries the reason under *Deliberately left thin*.
|
|
682
839
|
|
|
683
|
-
**Settings.** The third section
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
|
717
|
-
|---|---|---|
|
|
718
|
-
| Bytefly startup TUI | Pi `settings.json` (`quietStartup`) | Off, On |
|
|
719
|
-
| Theme | Pi `settings.json` (`theme`) | `system`, `bytefly-dark`, `bytefly-light` |
|
|
720
|
-
| Desktop notifications | `notify.enabled` | Off, On |
|
|
721
|
-
| Turn finished | `notify.turnFinished` | Off, On |
|
|
722
|
-
| Needs input | `notify.needsInput` | Off, On |
|
|
723
|
-
| Job finished | `notify.jobFinished` | Off, On |
|
|
724
|
-
| Watcher matched | `notify.matchFound` | Off, On |
|
|
725
|
-
| Wake when a job finishes | `job.wakeOnFinish` | Off, On |
|
|
726
|
-
| Automatic snapshots | `rewind.autoSnapshots` | Off, On |
|
|
727
|
-
| Proactive health check | `doctor.proactive` | Off, On |
|
|
728
|
-
| Currency | `price.currency.code` | CNY, USD |
|
|
729
|
-
| Session budget | `price.budget` | Number, `0` = off |
|
|
840
|
+
**Settings.** The third section is the same frame over the curated preferences,
|
|
841
|
+
grouped by what they do rather than by which file holds them: `Startup (2)`,
|
|
842
|
+
`Notifications (5)`, `Session (3)`, and `Price (2)`. It is the shortlist a
|
|
843
|
+
session changes: twelve preferences, each with its value in one aligned column
|
|
844
|
+
instead of beside its label, so a column of values can be read down. Sixteen
|
|
845
|
+
entries — twelve rows and their four headings — fit a 24-row terminal when the
|
|
846
|
+
block sits beside the list; on a narrower one the list scrolls and the block
|
|
847
|
+
keeps its three rows. The frame never grows past the tallest section, however
|
|
848
|
+
tall the terminal is. In Project scope the two app rows drop out and the note
|
|
849
|
+
`App settings are Global only.` stands above the list.
|
|
850
|
+
|
|
851
|
+
The block carries `Now` with the value, `About` with the preference's own
|
|
852
|
+
description, and `Stored in <origin> · <file>` — `Global`, `Project`,
|
|
853
|
+
`Inherited from Global`, or `Default`, with the file that supplied the value
|
|
854
|
+
(`~/.pi/agent/settings.json` for an app row, the active scope's `bytefly.json`
|
|
855
|
+
otherwise). `J` on a `bytefly.json` row appends that section as the active scope
|
|
856
|
+
stores it, under a `── notify ──` rule.
|
|
857
|
+
|
|
858
|
+
<img src="../../assets/screens/bytefly-settings.png" alt="The /bytefly Settings section at 120 columns: the `Startup (2)`, `Notifications (5)`, `Session (3)`, and `Price (2)` groups with each value in one aligned column, the `Extensions 9 · Skills 0 · Settings 12` tabs with `writes Global` at the right, and the focused row's block beside the list — its value, description, and the file the value is stored in" width="100%">
|
|
859
|
+
|
|
860
|
+
| Group | Row | Source | Values |
|
|
861
|
+
|---|---|---|---|
|
|
862
|
+
| Startup | Startup screen | Pi `settings.json` (`quietStartup`) | Off, On |
|
|
863
|
+
| Startup | Theme | Pi `settings.json` (`theme`) | `system`, `bytefly-dark`, `bytefly-light` |
|
|
864
|
+
| Notifications | Desktop notifications | `notify.enabled` | Off, On |
|
|
865
|
+
| Notifications | When a turn ends | `notify.turnFinished` | Off, On |
|
|
866
|
+
| Notifications | When the agent needs you | `notify.needsInput` | Off, On |
|
|
867
|
+
| Notifications | When a job ends | `notify.jobFinished` | Off, On |
|
|
868
|
+
| Notifications | When a watcher matches | `notify.matchFound` | Off, On |
|
|
869
|
+
| Session | Resume after a job | `job.wakeOnFinish` | Off, On |
|
|
870
|
+
| Session | Snapshot before a turn | `rewind.autoSnapshots` | Off, On |
|
|
871
|
+
| Session | Health check at startup | `doctor.proactive` | Off, On |
|
|
872
|
+
| Price | Currency | `price.currency.code` | `CNY (¥)`, `USD ($)` |
|
|
873
|
+
| Price | Session budget | `price.budget` | `Off`, or the amount as `¥5.00` |
|
|
730
874
|
|
|
731
875
|
Choosing **Currency** also writes that currency's default precision
|
|
732
876
|
(`price.currency.decimals`). Both stay editable in `bytefly.json` afterwards, so
|
|
@@ -743,44 +887,40 @@ and is replaced by the next choice here, so manage those in Pi's `/settings` →
|
|
|
743
887
|
|
|
744
888
|
`Space` (or `Enter`) changes the focused row: a boolean toggles, an enum cycles
|
|
745
889
|
forward, and the one text row — **Session budget** — opens an inline editor on its
|
|
746
|
-
amount. `u` deletes the focused row's key so its default applies again (
|
|
747
|
-
at its default.` when nothing is stored in that scope; an inherited
|
|
748
|
-
says so instead
|
|
749
|
-
section as the active scope stores it — the
|
|
750
|
-
leaves to JSON.
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
the same reload confirm as an extension or skill toggle.
|
|
757
|
-
|
|
758
|
-
The list is capped at thirteen rows so the screen keeps fitting a 24-row
|
|
759
|
-
terminal: adding a setting means removing one (`panel/panel.test.ts` holds the
|
|
890
|
+
amount. `u` deletes the focused row's key so its default applies again (`<row>
|
|
891
|
+
is already at its default.` when nothing is stored in that scope; an inherited
|
|
892
|
+
Project value says so instead, and an app row answers that Pi has no unset), and
|
|
893
|
+
`J` appends the focused row's whole section as the active scope stores it — the
|
|
894
|
+
only view of the keys this screen leaves to JSON. A successful change marks the
|
|
895
|
+
block `Saved · reload to apply` and puts `unsaved changes` in the header, and
|
|
896
|
+
closing offers the same reload confirm as an extension or skill toggle.
|
|
897
|
+
|
|
898
|
+
The list is capped at twelve rows so the screen keeps fitting a 24-row
|
|
899
|
+
terminal: adding a setting means removing one (`panel/settings.test.ts` holds the
|
|
760
900
|
ceiling). Everything else stays in `bytefly.json` — the tuning numbers, the
|
|
761
901
|
cosmetic labels, and the Pi preferences Pi's own `/settings` owns — and
|
|
762
902
|
`test/settings-coverage.test.ts` keeps the split honest: every loader key is
|
|
763
|
-
either a row or a declared JSON-only edit with the reason it left.
|
|
764
|
-
`bytefly.json` sections therefore have no row at all
|
|
765
|
-
`
|
|
903
|
+
either a row or a declared JSON-only edit with the reason it left. Most
|
|
904
|
+
`bytefly.json` sections therefore have no row at all — `chrome`, `goal`, `watch`,
|
|
905
|
+
`worktree`, and `memory` among them — just as `notify.title`, `doctor.timeoutMs`,
|
|
766
906
|
`price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`,
|
|
767
907
|
`job.detachedByDefault`, and `watch.wakeOnMatch` inside sections that do. Each is
|
|
768
|
-
documented in [`docs/configuration.md`](
|
|
908
|
+
documented in [`docs/configuration.md`](../configuration.md).
|
|
769
909
|
|
|
770
910
|
Two of the five sections belong to other extensions (`rewind` and `job`). The
|
|
771
911
|
screen cannot import their normalizers, so it reports the leaf as
|
|
772
912
|
the file states it and declares the loader's default; the same test holds the
|
|
773
913
|
catalogue to every loader's defaults and bounds in both directions.
|
|
774
914
|
|
|
775
|
-
**
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
915
|
+
**Startup screen** is the one row whose label differs from the Pi key it writes:
|
|
916
|
+
On writes `"quietStartup": true` (bytefly's header replaces Pi's startup detail),
|
|
917
|
+
and Off writes `false` (Pi's built-in header stays). A hand-set `"header"` reads
|
|
918
|
+
Off, because it keeps Pi's header; the next toggle replaces it with `true` or
|
|
919
|
+
`false`.
|
|
780
920
|
|
|
781
921
|
App rows are **Global only**: Pi's setters for them write the personal
|
|
782
922
|
`settings.json`, and only resource paths have public project setters. Project
|
|
783
|
-
scope therefore lists the
|
|
923
|
+
scope therefore lists the ten `bytefly.json` rows and a
|
|
784
924
|
`App settings are Global only.` note rather than promising a write that cannot
|
|
785
925
|
happen. A `bytefly.json` row writes one leaf in the selected scope (a depth-1
|
|
786
926
|
key, or a nested one such as `price.currency.code`) through a per-key writer, so
|
|
@@ -792,19 +932,19 @@ The non-`tui` form prints the headline and one `Label: Value` row per line, in
|
|
|
792
932
|
screen order:
|
|
793
933
|
|
|
794
934
|
```
|
|
795
|
-
bytefly: Settings · Global ·
|
|
796
|
-
|
|
935
|
+
bytefly: Settings · Global · 12 settings
|
|
936
|
+
Startup screen: Off
|
|
797
937
|
Theme: bytefly-dark
|
|
798
938
|
Desktop notifications: On
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
939
|
+
When a turn ends: On
|
|
940
|
+
When the agent needs you: On
|
|
941
|
+
When a job ends: On
|
|
942
|
+
When a watcher matches: On
|
|
943
|
+
Resume after a job: On
|
|
944
|
+
Snapshot before a turn: On
|
|
945
|
+
Health check at startup: On
|
|
806
946
|
Currency: CNY (¥)
|
|
807
|
-
Session budget: 5
|
|
947
|
+
Session budget: ¥5.00
|
|
808
948
|
```
|
|
809
949
|
|
|
810
950
|
The doctor side probes every declared extension and reports each check as `ok`,
|
|
@@ -837,27 +977,38 @@ headline; a named extension prints its full findings instead.
|
|
|
837
977
|
|
|
838
978
|
### Keys
|
|
839
979
|
|
|
980
|
+
One table in [`panel/tui/keys.ts`](../../extensions/bytefly/panel/tui/keys.ts)
|
|
981
|
+
drives the bindings, the hint row, and the `?` key list, so a key cannot drift
|
|
982
|
+
from its hint or its help line. The hint row is per section and drops whole hints
|
|
983
|
+
from the right as the width runs out, so `Esc` and the section keys survive on a
|
|
984
|
+
narrow terminal; the Settings section's row is the shorter one.
|
|
985
|
+
|
|
840
986
|
| Key | Effect |
|
|
841
987
|
|---|---|
|
|
842
|
-
|
|
|
843
|
-
| `
|
|
844
|
-
| `
|
|
845
|
-
| `
|
|
988
|
+
| `Esc` (`Ctrl+C`) | Close the screen. |
|
|
989
|
+
| `←` / `→`, `h` / `l`, `Tab` / `Shift+Tab` | Previous or next section — Extensions, Skills, Settings — wrapping at the ends. |
|
|
990
|
+
| `↑` / `↓`, `j` / `k` | Move to the previous or next row. |
|
|
991
|
+
| `PgUp` / `PgDn` | Move a page. |
|
|
992
|
+
| `Home` / `End`, `g` / `G` | Jump to the first or last row. |
|
|
993
|
+
| `[` / `]` | Jump to the previous or next group; a group heading is never the focus. |
|
|
994
|
+
| `Space` | Toggle the focused extension or skill; change the focused value (Settings). |
|
|
995
|
+
| `Enter` | Expand or collapse the focused row's findings, or a skill's description; change the focused value, or open the editor on a text row (Settings). |
|
|
996
|
+
| `/` | Filter the rows by text; the query applies as it is typed and `Esc` clears it. |
|
|
997
|
+
| `!` | Show only the rows that need attention; on Settings, only values changed from their default. |
|
|
998
|
+
| `s` | Switch where a change is written: Global or Project. |
|
|
999
|
+
| `x` | Drop the focused resource's Project override, so Global applies again (Extensions and Skills, Project scope only). |
|
|
1000
|
+
| `r` | Re-probe every extension's requirements (Extensions only); a second `r` while one is in flight is ignored. |
|
|
1001
|
+
| `R` | Reload now, to apply what you changed; with nothing pending it says so instead. |
|
|
846
1002
|
| `u` | Delete the focused setting's key so its default applies again (Settings, `bytefly.json` rows). |
|
|
847
|
-
| `J` | Show or hide the focused row's whole section as stored (Settings
|
|
848
|
-
|
|
|
849
|
-
| `←` / `→`, `Home` / `End` (`Ctrl+A` / `Ctrl+E`) | Move the editor's caret while a text row is being edited. |
|
|
1003
|
+
| `J` | Show or hide the focused row's whole `bytefly.json` section as stored (Settings). |
|
|
1004
|
+
| `?` | Show the key list in the focused row's block; `?` again hides it. |
|
|
1005
|
+
| `←` / `→`, `Home` / `End` (`Ctrl+A` / `Ctrl+E`) | Move the editor's caret while a text row or the filter is being edited. |
|
|
850
1006
|
| `Backspace` / `Delete`, `Ctrl+U` | Edit the buffer: delete a character, or clear it. |
|
|
851
1007
|
| `Enter` / `Esc` (editing) | Save the buffer, or cancel and restore the stored value. |
|
|
852
|
-
| `Tab` | Switch between Global and Project scope, in any section. |
|
|
853
|
-
| `r` | Re-probe the doctor (Extensions). |
|
|
854
|
-
| `↑`/`↓`, `j`/`k` | Move the selection, in any section. |
|
|
855
|
-
| `PgUp`/`PgDn` | Move a page, in any section. |
|
|
856
|
-
| `g` / `G`, `Home` / `End` | Jump to the first or last row, in any section. |
|
|
857
|
-
| `Esc` / `Ctrl+C` | Close the screen. |
|
|
858
1008
|
|
|
859
|
-
|
|
860
|
-
|
|
1009
|
+
`Esc` clears an open filter or editor before it closes the screen, so nothing
|
|
1010
|
+
typed is left narrowing the list or half-written. Mouse wheel scrolling and
|
|
1011
|
+
clicking a row to focus it work; every action also has a keyboard path.
|
|
861
1012
|
|
|
862
1013
|
### What is checked
|
|
863
1014
|
|
|
@@ -884,10 +1035,10 @@ the same entry in `lib/requirements.ts`, so the two cannot drift.
|
|
|
884
1035
|
|
|
885
1036
|
## Notifications
|
|
886
1037
|
|
|
887
|
-
The notify capability exists for unattended runs: start a
|
|
888
|
-
terminal, and get a desktop notification when Pi needs you
|
|
889
|
-
It fires on four events, each independently switchable in
|
|
890
|
-
of `bytefly.json` (see [Configuration](#configuration)):
|
|
1038
|
+
The notify capability is off by default and exists for unattended runs: start a
|
|
1039
|
+
long turn, leave the terminal, and get a desktop notification when Pi needs you
|
|
1040
|
+
— or when it is done. It fires on four events, each independently switchable in
|
|
1041
|
+
the `notify` section of `bytefly.json` (see [Configuration](#configuration)):
|
|
891
1042
|
|
|
892
1043
|
- **A run settled** (`agent_settled`). Pi finished the turn and waits for the
|
|
893
1044
|
next message. An aborted run is skipped: interrupting with Escape means the
|
|
@@ -896,10 +1047,10 @@ of `bytefly.json` (see [Configuration](#configuration)):
|
|
|
896
1047
|
`ask_user_question`, a plan review, a subagent approval. A prompt opened while
|
|
897
1048
|
idle is a command the user just typed, so it does not fire; the run boundary
|
|
898
1049
|
is what separates "the agent is asking" from "the user is asking".
|
|
899
|
-
- **A background job finished.** The [job](
|
|
1050
|
+
- **A background job finished.** The [job](./job.md) extension announces each
|
|
900
1051
|
terminal transition on the shared `pi.events` bus
|
|
901
1052
|
(`my-pi-agent/job-finished`); bytefly listens and never imports it.
|
|
902
|
-
- **A watcher matched.** A [watch](
|
|
1053
|
+
- **A watcher matched.** A [watch](./watch.md) whose `wake` is on matched, and
|
|
903
1054
|
announced it on `my-pi-agent/watch-match` with the cycle's
|
|
904
1055
|
count, the watcher, and its newest line. The body names that line, sanitized and
|
|
905
1056
|
clipped to 80 characters, because the line is the alert: a watch usually tails a
|
|
@@ -1018,17 +1169,27 @@ release without a restart. Opening the control center never checks: the screen h
|
|
|
1018
1169
|
no update surface, and the only request paths are `session_start` and this
|
|
1019
1170
|
command.
|
|
1020
1171
|
|
|
1172
|
+
`/bytefly upgrade` is the half that writes. It asks for a confirmation and then
|
|
1173
|
+
calls the package manager's own `update()`: the same manager that reads the
|
|
1174
|
+
packages configured in `settings.json`, owns the install root, and honours a
|
|
1175
|
+
project's `npmCommand`, so no shell and no `pi update` command is involved. Pi
|
|
1176
|
+
skips a pinned npm version, and `PI_OFFLINE` skips the whole path. The manager
|
|
1177
|
+
returns nothing, so the answer is a re-read of what is left: `every configured
|
|
1178
|
+
package is updated — reload to use the new version`, or a warning when a package
|
|
1179
|
+
is still behind after a successful run; a failed install prints the manager's own
|
|
1180
|
+
message. The running session keeps the old code loaded until it reloads, which is
|
|
1181
|
+
why the line says so, and each source the manager reports is shown while it runs.
|
|
1182
|
+
|
|
1021
1183
|
## Limitations
|
|
1022
1184
|
|
|
1023
|
-
- **
|
|
1185
|
+
- **The Startup screen row is the startup surface only.** It installs or removes
|
|
1024
1186
|
bytefly's startup header and the proactive doctor notice; the footer, turn
|
|
1025
1187
|
rule, and transcript renderers stay on. Use `PI_DISABLED_EXTENSIONS=bytefly`
|
|
1026
1188
|
(or `pi config`) to turn off all of bytefly.
|
|
1027
|
-
- **App settings are Global only.** Pi's setters for
|
|
1028
|
-
`quietStartup` (the **
|
|
1029
|
-
`
|
|
1030
|
-
|
|
1031
|
-
manage.
|
|
1189
|
+
- **App settings are Global only.** Pi's setters for the two app preferences
|
|
1190
|
+
the screen carries — `quietStartup` (the **Startup screen** row) and
|
|
1191
|
+
`theme` — write the personal `settings.json`; the screen hides those rows in
|
|
1192
|
+
Project scope rather than writing a file Pi cannot manage.
|
|
1032
1193
|
- **The Theme row offers only this package's palettes.** `system`,
|
|
1033
1194
|
`bytefly-dark`, and `bytefly-light` are the whole cycle; Pi's built-ins and any
|
|
1034
1195
|
user, project, or other package's theme stay in Pi's `/settings` → **Theme**,
|
|
@@ -1041,7 +1202,7 @@ command.
|
|
|
1041
1202
|
- **The list is a shortlist, not the whole document.** A row is one boolean,
|
|
1042
1203
|
enum, string, or number; the tuning numbers, the labels, and the Pi
|
|
1043
1204
|
preferences `/settings` owns stay in their files, and the catalogue is capped
|
|
1044
|
-
at
|
|
1205
|
+
at twelve rows so the screen fits a 24-row terminal. `doctor.skip` (an
|
|
1045
1206
|
array), the `rates` table, and `price.peak` (a nested object) could never be a
|
|
1046
1207
|
row; the rest are declared JSON-only with their reason in
|
|
1047
1208
|
`test/settings-coverage.test.ts`.
|
|
@@ -1049,16 +1210,18 @@ command.
|
|
|
1049
1210
|
because a two-column glyph would push every railed body one cell right; the
|
|
1050
1211
|
loader drops anything else, and the former four-glyph menu is the
|
|
1051
1212
|
configuration reference's example list.
|
|
1052
|
-
- **`doctor`, `settings`, `skills`, and `
|
|
1053
|
-
`/bytefly doctor` always selects the report, so an extension
|
|
1054
|
-
`doctor` cannot be narrowed to by name; `settings`, `skills`,
|
|
1055
|
-
reserved the same way.
|
|
1213
|
+
- **`doctor`, `settings`, `skills`, `update`, and `upgrade` are reserved first
|
|
1214
|
+
arguments.** `/bytefly doctor` always selects the report, so an extension
|
|
1215
|
+
literally named `doctor` cannot be narrowed to by name; `settings`, `skills`,
|
|
1216
|
+
`update`, and `upgrade` are reserved the same way.
|
|
1056
1217
|
- **The picker manages the `extensions` and `skills` resource types.** Prompts
|
|
1057
1218
|
and themes stay with Pi's own `pi config`.
|
|
1058
1219
|
- **Built-in extensions are not listed** (`builtin:mcp`, `builtin:codemode`, …):
|
|
1059
1220
|
their authoritative names are not exposed to extensions. Use `pi config`.
|
|
1060
|
-
- **
|
|
1061
|
-
|
|
1221
|
+
- **Nothing is installed or removed here.** `/bytefly upgrade` runs Pi's own
|
|
1222
|
+
update for the packages configured in `settings.json`; adding a package is
|
|
1223
|
+
still `pi install`, removing one is `pi remove`, and Pi itself is still
|
|
1224
|
+
`pi update`.
|
|
1062
1225
|
- **The update list is Pi's.** Only packages configured in `settings.json` are
|
|
1063
1226
|
checked; `pi -e .`, a temporary checkout, and other unmanaged loads get no
|
|
1064
1227
|
update prompt. The version arrow and release URL still come from npm's
|
|
@@ -1077,7 +1240,9 @@ command.
|
|
|
1077
1240
|
restores both on shutdown. A future Pi that changes either method shape makes
|
|
1078
1241
|
that shim inert, and Pi's own block can come back.
|
|
1079
1242
|
- **No auto-update, and the release URL is text only.** The notice names a
|
|
1080
|
-
command instead of running one
|
|
1243
|
+
command instead of running one; the only path that writes is `/bytefly
|
|
1244
|
+
upgrade`, and it waits for a confirmation. The notice renderer cannot open a
|
|
1245
|
+
link, so
|
|
1081
1246
|
the release row prints the URL and nothing more — no changelog body, no way to
|
|
1082
1247
|
click through from the transcript. Pi's optional release note arrives as one
|
|
1083
1248
|
sanitized `release notes` row, so a multi-paragraph note is flattened and
|
|
@@ -1097,10 +1262,11 @@ command.
|
|
|
1097
1262
|
Anthropic's 2× one-hour cache write are not modelled; switch to `USD` mode
|
|
1098
1263
|
to use Pi's recorded cost for those models.
|
|
1099
1264
|
- **No FX conversion.** The two modes are separate methods; neither converts
|
|
1100
|
-
one currency into the other. A model is priced only by the selected method
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1265
|
+
one currency into the other. A model is priced only by the selected method, and
|
|
1266
|
+
a model neither method can price is named — by key, in the footer, in
|
|
1267
|
+
`/bytefly prices`, and in one notice — instead of being quietly left out. What
|
|
1268
|
+
is *not* built is a table for another provider: rates are sourced data, and
|
|
1269
|
+
`price.rates` is where they go.
|
|
1104
1270
|
- **Two built-in footer indicators cannot be reproduced.** Pi's `(auto)` marks
|
|
1105
1271
|
that auto-compaction is on, and its `(sub)` marks a subscription-backed
|
|
1106
1272
|
provider. Auto-compaction is session state on Pi's own session object, and
|
|
@@ -1147,7 +1313,7 @@ command.
|
|
|
1147
1313
|
`bytefly.json`.
|
|
1148
1314
|
- No per-model cost breakdown and no on-screen marker for which tariff or
|
|
1149
1315
|
which source produced a number.
|
|
1150
|
-
- No todo-count segment; the [todo](
|
|
1316
|
+
- No todo-count segment; the [todo](./todo.md) widget already shows progress.
|
|
1151
1317
|
- No shelling out for git ahead/behind; the footer data provider exposes only
|
|
1152
1318
|
the branch.
|
|
1153
1319
|
- No session or model data in the header: it shows the nameplate and the grouped
|
|
@@ -1176,7 +1342,7 @@ rather than showing a wrong value.
|
|
|
1176
1342
|
|
|
1177
1343
|
| Integration point | Details |
|
|
1178
1344
|
|---|---|
|
|
1179
|
-
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **
|
|
1345
|
+
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **Startup screen** row). `false`, `"header"`, and unset call `setHeader(undefined)`, leaving Pi's built-in header in place. The nameplate insets by Pi's `outputPad` (read through `pi.getSettings()`), so it sits on the transcript margin, and the help hangs one body indent inside it. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. The factory reads `tui.terminal.rows` on every render, so the height ladder in `header/config.ts` sheds help groups and then the leading blank row as the terminal shortens (unknown height keeps the full header). The chrome version gains `↑<latest>` from the `UpdateSource`, the agent line gains Pi's own `↑<latest>` from the second store, and `registerHeader` returns a `refresh()` handle that re-installs the last context's header when either value arrives. |
|
|
1180
1346
|
| Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
|
|
1181
1347
|
| User message | `pi.registerMarkdownTransformer` puts a two-row `You` nameplate (the label over a full-width rule) above each user message; one padded level-2 heading carries the accent through `mdHeading` for both rows, and the shipped themes set `userMessageBg` to the terminal default, so the block has no fill. Pi renders the result as Markdown, so the surface adds no component or color of its own. |
|
|
1182
1348
|
| Notice | `registerMessageRenderer(NOTICE_TYPE)` draws every shared transcript notice at the margin from its `details`; the headline stays at the margin with its title painted by the notice's own severity, and its rows hang from the transcript rail, painted by the notice's worst severity, whose glyph comes from the shared `RailSource`. `job` and `watch` post one when their work settles, and `doctor` posts one at `session_start` for a missing hard requirement. The type and shape come from `lib/notice.ts`. A message without `details` falls back to Pi's default custom-message box. |
|
|
@@ -1187,12 +1353,12 @@ rather than showing a wrong value.
|
|
|
1187
1353
|
| 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. |
|
|
1188
1354
|
| Picker discovery | `SettingsManager.create(...)` plus `DefaultPackageManager.resolve({ onMissing: "skip" })`, both public exports; both views drop `bytefly`'s own entrypoint. |
|
|
1189
1355
|
| Picker writes | `SettingsManager` setters (`setExtensionPaths`, `setPackages`, `setProjectExtensionPaths`, `setProjectPackages`) then `flush()`; `ctx.reload()` after the screen closes when changes are pending. |
|
|
1190
|
-
| Settings writes | App rows call `SettingsManager` setters (`setQuietStartup`, `
|
|
1356
|
+
| 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. |
|
|
1191
1357
|
| 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. |
|
|
1192
1358
|
| 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. |
|
|
1193
1359
|
| Status routing | Reads `footerData.getExtensionStatuses()` (a custom footer replaces the built-in one entirely); `worktree` routes to line 1, plan/alert statuses to line 2's trailing slot. |
|
|
1194
1360
|
| 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. |
|
|
1195
|
-
| Update check | `session_start` in `tui` mode installs a suppression on `DefaultPackageManager.prototype.checkForAvailableUpdates`, then reads `<agentDir>/bytefly/update.json`. A fresh entry whose key matches the cwd and effective package sources is recorded without a package-manager call; otherwise bytefly fires `fetchAvailableUpdates()` without awaiting, resolves this package's version through `fetchLatestVersion()` when Pi reports it, writes the snapshot, and records it. `onUpdate` re-installs the header, and `pi.sendMessage(updateNotice(...))` posts the one notice with its version arrow and release URL. `PI_OFFLINE` paints the cached marker only. `/bytefly update` calls the returned `UpdateHandle.recheck()`, which bypasses the window and returns an `UpdateOutcome`;
|
|
1361
|
+
| 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. |
|
|
1196
1362
|
| 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. |
|
|
1197
1363
|
| Data sources | `footerData.getGitBranch()`, `footerData.getAvailableProviderCount()`, `ctx.getContextUsage()`, `ctx.sessionManager.getEntries()`, `ctx.sessionManager.getSessionName()`, `ctx.model`; subscribes to `footerData.onBranchChange` to repaint. |
|
|
1198
1364
|
| 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`. |
|
|
@@ -1276,9 +1442,9 @@ rather than showing a wrong value.
|
|
|
1276
1442
|
entry renderer none and adds its component raw, so bytefly's blocks inset
|
|
1277
1443
|
themselves by that pad: the tool frame and the notice take it from Pi, and the
|
|
1278
1444
|
turn separator reads the last value a sibling observed (`pad.ts`). Pi's setting
|
|
1279
|
-
is the only knob — bytefly adds no padding of its own. The footer
|
|
1280
|
-
|
|
1281
|
-
a transcript-only glyph.
|
|
1445
|
+
is the only knob — bytefly adds no padding of its own. The footer draws no
|
|
1446
|
+
rule of its own: it joins its chips with the shared ` · `, and the rail (`╎`)
|
|
1447
|
+
stays a transcript-only glyph.
|
|
1282
1448
|
- **The header is a nameplate, not a dashboard.** Pi's built-in brand colors are
|
|
1283
1449
|
fixed, so the mark ignores the active theme; bytefly's header draws a two-tone
|
|
1284
1450
|
mark from the `accent`/`warn` roles, a signature rule whose accent lead sits
|
|
@@ -1290,24 +1456,41 @@ rather than showing a wrong value.
|
|
|
1290
1456
|
terminal: the height ladder drops whole help groups, then the leading blank
|
|
1291
1457
|
row, before the nameplate gives up anything, so a short pane spends its rows
|
|
1292
1458
|
on the transcript instead of chrome.
|
|
1293
|
-
- **Two lines,
|
|
1294
|
-
|
|
1295
|
-
|
|
1459
|
+
- **Two lines, one job each: state and meters.** Line 1 is state (`pwd` and the
|
|
1460
|
+
session name left; the alert, the modes, then `⎇` branch, `⑂` worktree and the
|
|
1461
|
+
ports right); line 2 is meters (the gauge and usage left; model and level
|
|
1462
|
+
right). The state chips change while a session runs, so they ride the line that
|
|
1463
|
+
has slack: the meters are the dense row, and a fact that moves to the top row is
|
|
1464
|
+
one the bottom row stops dropping to fit. It keeps "where am I / what state"
|
|
1465
|
+
separate from "how much am I burning".
|
|
1296
1466
|
- **Child spend is a second figure.** The footer never adds a subagent's tokens to
|
|
1297
1467
|
the session's; it prices the `my-pi-agent/subagent-finished` events with the
|
|
1298
1468
|
same pricer and renders them as `↳`, so "this session" keeps meaning the
|
|
1299
1469
|
dispatching process and the delegated work stays visible beside it.
|
|
1300
|
-
- **The gauge is anchored at column 0
|
|
1301
|
-
context percentage left and right as plan mode came
|
|
1302
|
-
|
|
1303
|
-
|
|
1470
|
+
- **The gauge is anchored at column 0, and nothing can displace it.** A leading
|
|
1471
|
+
mode slot used to push the context percentage left and right as plan mode came
|
|
1472
|
+
and went, which is why the mode chip trailed the meters after a `│`; moving the
|
|
1473
|
+
mode slot to the state line leaves the gauge as the resource line's first
|
|
1474
|
+
segment, so the percentage cannot move at all.
|
|
1304
1475
|
- **Statuses are routed, not repeated.** The built-in footer renders every
|
|
1305
1476
|
`setStatus` value on its own line, so the bar sorts them by meaning instead:
|
|
1306
|
-
`worktree` and `browse` are location, so the `◉ <port>` chip sits
|
|
1307
|
-
branch and `⑂` worktree
|
|
1308
|
-
|
|
1309
|
-
|
|
1477
|
+
`worktree` and `browse` are location, so the `◉ <port>` chip sits behind `⎇`
|
|
1478
|
+
branch and `⑂` worktree; the `board` key is location too, and the two ports
|
|
1479
|
+
are one segment because they are one fact, so they share a weight and a floor;
|
|
1480
|
+
a plan is a mode, so it leads the state line beside them; a failed job is an
|
|
1481
|
+
alert, so it is its own segment ahead of both. The
|
|
1482
|
+
[wechat](./wechat.md) extension publishes `✆ wechat` while its bridge runs,
|
|
1310
1483
|
which is why the bar has to render `getExtensionStatuses()` at all.
|
|
1484
|
+
- **A state chip leads its zone, so the zone does not move under it.** The right
|
|
1485
|
+
zone is right-aligned: a chip appended to it would push the branch and the
|
|
1486
|
+
worktree label left every time a mode came and went, while a chip prepended to
|
|
1487
|
+
it grows into the empty columns. That is the same stability argument the gauge
|
|
1488
|
+
gets from sitting at column 0, applied to the row that changes.
|
|
1489
|
+
- **A failure is never the thing that drops.** The alert segment is the one
|
|
1490
|
+
non-droppable chip: every other fact can be read again — the branch from git,
|
|
1491
|
+
the mode from the session, the spend from `/bytefly prices` — while a failed
|
|
1492
|
+
job that scrolled off the bar is a failure nobody is looking at. It keeps its
|
|
1493
|
+
count (`✗1`) when it compacts.
|
|
1311
1494
|
- **Segments degrade; they do not clip.** Each `Segment` carries progressively
|
|
1312
1495
|
shorter `forms` and a `weight`; the layout advances the lowest-priority form
|
|
1313
1496
|
or drops the lowest-priority segment, and only truncates once everything is
|
|
@@ -1317,15 +1500,23 @@ rather than showing a wrong value.
|
|
|
1317
1500
|
non-zero usage, so it reads full only at 100% and a small percentage never
|
|
1318
1501
|
disappears; unknown usage draws no gauge at all. Only at extreme widths does
|
|
1319
1502
|
`truncateToWidth` clip the remaining text.
|
|
1320
|
-
- **Separators shrink to a single space.**
|
|
1321
|
-
|
|
1322
|
-
never collide and the ellipsis never replaces a
|
|
1503
|
+
- **Separators shrink to a single space.** Every segment is joined by the same
|
|
1504
|
+
padded ` · `, which collapses to one space before `truncateToWidth` applies, so
|
|
1505
|
+
adjacent segments never collide and the ellipsis never replaces a separator
|
|
1506
|
+
with nothing after it.
|
|
1323
1507
|
- **Statuses compact with their colour.** A themed status's compact icon form
|
|
1324
1508
|
reattaches its opening and closing SGR sequences around the visible text, so a
|
|
1325
1509
|
red `✗1` stays red instead of losing its colour exactly when the bar tightens.
|
|
1326
1510
|
A two-token `icon count` badge (for `rewind`: `↺ 2`) compacts to `↺2`, keeping
|
|
1327
|
-
the count.
|
|
1328
|
-
|
|
1511
|
+
the count. A mode is droppable, so it goes before the branch and long before
|
|
1512
|
+
the model is clipped; only an alert is not.
|
|
1513
|
+
- **A budget is a position, not a second figure.** With `price.budget` set, the
|
|
1514
|
+
cost segment reads `$0.31/$5` and turns `warn` once the spend reaches the
|
|
1515
|
+
ceiling, which is the same `budgetState` condition the notice fires on, so the
|
|
1516
|
+
bar cannot call a session over budget that the notice has not. The ceiling is
|
|
1517
|
+
formatted by its own `formatLimit` — the number the user typed, with trailing
|
|
1518
|
+
zeros dropped — while the spend keeps the currency's precision; both the bar
|
|
1519
|
+
and the notice use it, so the two cannot disagree about one figure.
|
|
1329
1520
|
- **Neutral by default; color means something.** A tool block carries no status
|
|
1330
1521
|
colour except the accent tool name and the status-coloured result rail; an
|
|
1331
1522
|
informational notice leads with `muted`; a failure is red only where the
|
|
@@ -1468,7 +1659,7 @@ columns, gauge), so the look follows the active theme.
|
|
|
1468
1659
|
| `header/identity.ts` | `IdentityInput` and `identityCells`: the agent and chrome cells, each with its `↑` marker, in the ladder that sheds the chrome marker, the chrome version, the chrome line, and finally the agent's marker with the row. |
|
|
1469
1660
|
| `header/register.ts` | Installs/restores the header and owns its session lifecycle. |
|
|
1470
1661
|
| `footer/register.ts` | Installs/restores the footer and owns its session lifecycle. |
|
|
1471
|
-
| `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, status keys, labels. |
|
|
1662
|
+
| `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, alert and plan status keys, labels. |
|
|
1472
1663
|
| `footer/types.ts` | `StatusSnapshot`, `Segment`, `LineSpec`, `UsageRecord`, and footer/TUI shapes. |
|
|
1473
1664
|
| `footer/collect/entries.ts` | Session entries → usage records, each resolved to the model in effect. |
|
|
1474
1665
|
| `footer/collect/snapshot.ts` | Snapshot assembly; memoized pricing scan, context estimate, and session name per branch leaf. |
|
|
@@ -1477,7 +1668,7 @@ columns, gauge), so the look follows the active theme.
|
|
|
1477
1668
|
| `footer/price/rates.ts` | Model-key matching: `createRateLookup` splits every key once, splits a key at its first slash (so an OpenRouter model id may contain one), matches exact and wildcard most-specific-first, and remembers the last record's model. |
|
|
1478
1669
|
| `footer/price/schedule.ts` | Peak-window parsing and evaluation in a configured zone. |
|
|
1479
1670
|
| `footer/price/price.ts` | Records → totals: rated cost in both modes, Pi's recorded cost as USD's fallback, the peak multiplier, and the count of records CNY could not rate. |
|
|
1480
|
-
| `footer/unpriced.ts` | The one notice a
|
|
1671
|
+
| `footer/unpriced.ts` | The one notice a session posts for records nothing could price: the models by key, the count that the two agree on (`recordsText`), and its OS-notification body. |
|
|
1481
1672
|
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd, the context role, truncation). |
|
|
1482
1673
|
| `footer/render/status.ts` | Status-chip transforms: `compactStatus` and `dropStatusDetail`. |
|
|
1483
1674
|
| `footer/render/segments.ts` | The segment builders: forms, weights, separators, roles. |
|
|
@@ -1502,22 +1693,26 @@ columns, gauge), so the look follows the active theme.
|
|
|
1502
1693
|
| `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the words, the tool singular/plural, and the tick interval. |
|
|
1503
1694
|
| `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape: the plain count and the `tool · N tools · elapsed` run line. |
|
|
1504
1695
|
| `working/register.ts` | Starts the tick on `turn_start`, tracks top-level tools on `tool_execution_start`, and cancels on `agent_end`/`session_shutdown`. |
|
|
1505
|
-
| `panel/types.ts` | `PanelSection` (`extensions`
|
|
1506
|
-
| `panel/join.ts` | The item/report union with the unambiguous-name
|
|
1507
|
-
| `panel/
|
|
1508
|
-
| `panel/
|
|
1696
|
+
| `panel/types.ts` | `PanelSection` (`extensions` \| `skills` \| `settings`), `PanelRow` with its optional skill info, `SkillInfo`, and `PanelModel`, the merged row model. |
|
|
1697
|
+
| `panel/join.ts` | The item/report union with the unambiguous-name naming rule — a row is `worktree`, and a directory claims a report only when one resource uses that name — plus unique row keys, groups, ordering, and the skills model that labels rows from `SKILL.md`. |
|
|
1698
|
+
| `panel/filter.ts` | The two filters as predicates and chips: a text query over a row's name, path, and source, the attention switch, and what the tab row says is on. |
|
|
1699
|
+
| `panel/format.ts` | Non-TUI text: the resource headline and grouped listing with a per-row verdict, the header's attention segments, the one `rowBadge` the screen and the listing share, the section segments and their order, the Settings counts/headline, and the flat Settings listing. |
|
|
1700
|
+
| `panel/settings.ts` | The curated Settings catalogue: the twelve descriptors in screen order, their four groups, the value labels (`Off`, `¥5.00`) and display origins, value cycling, stored-value mapping, validation, plus the per-section readers that resolve a row's leaf over the global and project documents. |
|
|
1509
1701
|
| `panel/settings-runtime.ts` | The Settings runtime: snapshot cache, scope guards, app setters, per-leaf `bytefly.json` writes, dirty state, and change listeners. |
|
|
1510
1702
|
| `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. |
|
|
1703
|
+
| `panel/prices.ts` | The `/bytefly prices` report: the unpriced models by key, the records behind each, and the one line saying where the keys go. It quotes no price — a rate is the user's to state. |
|
|
1511
1704
|
| `panel/skills.ts` | Skill metadata through Pi's own `loadSkills`, keyed by resolved path, plus the deduplicated paths both discovery views read. |
|
|
1512
|
-
| `panel/tui.ts` | `PanelComponent
|
|
1513
|
-
| `panel/tui/
|
|
1514
|
-
| `panel/tui/
|
|
1515
|
-
| `panel/tui/
|
|
1516
|
-
| `panel/tui/
|
|
1705
|
+
| `panel/tui.ts` | `PanelComponent`: the section switch, the three cursors and focus keys, the filter and help state, the toggle chain, and the one render that hands the frame its header, tabs, rows, and block. |
|
|
1706
|
+
| `panel/tui/keys.ts` | The one key table: each binding with the sections that offer it, the hint row they produce, and the `?` help block, so a key cannot drift from its hint or its help line. |
|
|
1707
|
+
| `panel/tui/panes.ts` | The two-pane arithmetic: the 96-column breakpoint, the side-pane width, one composed row with its `╎` divider, and the clip that ends a block with `… N more lines`. |
|
|
1708
|
+
| `panel/tui/side-pane.ts` | The focused row's block in both layouts: name and verdict, findings, `Path`, `Source`, `State`, `Health`, a setting's `Now`/`About`/`Stored in`, the JSON pane, and the saved marker. |
|
|
1709
|
+
| `panel/tui/section-view.ts` | What the screen derives from the session: the tab counts, the one body height, the header's attention, the filter chips, the empty label, and the merged model for a list section. |
|
|
1710
|
+
| `panel/tui/list-view.ts` | The resource row grammar only: the checkbox, the status glyph, the name, and the verdict column. |
|
|
1711
|
+
| `panel/tui/settings-view.ts` | The settings row — checkbox, label, value in its measured column, the editing cell — and the editor's hint row. |
|
|
1517
1712
|
| `panel/tui/entries.ts` | The flat display entries per section and the stable focus keys. |
|
|
1518
1713
|
| `panel/tui/editing.ts` | The text-row editor's key map: caret moves, delete, clear, commit, cancel. |
|
|
1519
|
-
| `panel/tui/frame.ts` | The
|
|
1520
|
-
| `panel/tui/settings-section.ts` | The Settings section's editor
|
|
1714
|
+
| `panel/tui/frame.ts` | The chrome — the header rule, the tab row with its counts, chips and scope, the group heading, the hint or notice row, and the saved marker — and the height law: one body target for all three sections, the range row, and the rows a short terminal sheds. |
|
|
1715
|
+
| `panel/tui/settings-section.ts` | The Settings section's state only: the text editor, the JSON pane, the write chain, and the reset. |
|
|
1521
1716
|
| `panel/tui/nav.ts` | The panel's cursor arithmetic and one read of a navigation key. |
|
|
1522
1717
|
| `panel/commands.ts` | `/bytefly`: one command for the screen sections, the `doctor` report, the settings and skills listings, and their text modes. |
|
|
1523
1718
|
| `picker/types.ts` | Picker host seams (`SettingsStore`, `ResourceResolver`, `Discovery`, `ResourceKind`), the app-settings setters, and row types. |
|
|
@@ -1574,15 +1769,20 @@ receipt's width ladder), its register/append/render/disable lifecycle
|
|
|
1574
1769
|
covered by the pure helpers (`picker/resources`), the toggle
|
|
1575
1770
|
transforms (`picker/toggle`), discovery with an injected factory
|
|
1576
1771
|
(`picker/discovery`), and the runtime state machine (`picker/runtime`). The
|
|
1577
|
-
unified screen is covered by its pure model merge (`panel/join`), its
|
|
1578
|
-
|
|
1579
|
-
(`panel/settings`), the scope-aware
|
|
1580
|
-
including a nested leaf write that
|
|
1581
|
-
and loader (`panel/skills`, on real
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1772
|
+
unified screen is covered by its pure model merge (`panel/join`), its two
|
|
1773
|
+
filters and their chips (`panel/filter`), its text formatter (`panel/format`),
|
|
1774
|
+
the settings catalogue and its cycling (`panel/settings`), the scope-aware
|
|
1775
|
+
settings runtime (`panel/settings-runtime`, including a nested leaf write that
|
|
1776
|
+
keeps its siblings), the skill metadata join and loader (`panel/skills`, on real
|
|
1777
|
+
`SKILL.md` files), the key table whose hints and help it holds to one source
|
|
1778
|
+
(`panel/keys`), the frame and the one height all three sections agree on
|
|
1779
|
+
(`panel/layout`), the row grammar and the focused-row block beside and under the
|
|
1780
|
+
list (`panel/views`), the two-pane split and its `… N more lines` clip
|
|
1781
|
+
(`panel/panes`), the editing key map (`tui/editing`), the component's frames,
|
|
1782
|
+
keys, sections, settings, and probe lifecycle (`panel/component`,
|
|
1783
|
+
`panel/component-input`, `panel/component-sections`,
|
|
1784
|
+
`panel/component-settings`, `panel/component-probing`), and the command through
|
|
1785
|
+
the bytefly factory (`panel/commands`) — eighteen suites in all.
|
|
1586
1786
|
The doctor surface is covered by its pure report
|
|
1587
1787
|
formatting (`doctor/format`), its config loader (`doctor/config`), and
|
|
1588
1788
|
registration, the proactive notice, the session cache, and `run_doctor`
|