@gavin-hu/my-pi-agent 0.8.1 → 0.10.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 +35 -8
- package/README.zh-CN.md +33 -8
- package/assets/bytefly.schema.json +17 -1
- package/assets/chrome.png +0 -0
- package/assets/file-browse.png +0 -0
- package/assets/job.png +0 -0
- package/assets/plan-review.png +0 -0
- package/assets/question.png +0 -0
- package/assets/rewind.png +0 -0
- package/assets/todo.png +0 -0
- package/assets/tool-renderings.png +0 -0
- package/assets/tools/ask_user_question.png +0 -0
- package/assets/tools/bash.png +0 -0
- package/assets/tools/edit.png +0 -0
- package/assets/tools/enter_plan_mode.png +0 -0
- package/assets/tools/enter_worktree.png +0 -0
- package/assets/tools/exit_plan_mode.png +0 -0
- package/assets/tools/exit_worktree.png +0 -0
- package/assets/tools/find.png +0 -0
- package/assets/tools/goal.png +0 -0
- package/assets/tools/grep.png +0 -0
- package/assets/tools/job.png +0 -0
- package/assets/tools/list_worktrees.png +0 -0
- package/assets/tools/ls.png +0 -0
- package/assets/tools/memory.png +0 -0
- package/assets/tools/notice.png +0 -0
- package/assets/tools/open_path.png +0 -0
- package/assets/tools/prune_worktrees.png +0 -0
- package/assets/tools/read.png +0 -0
- package/assets/tools/read_doc.png +0 -0
- package/assets/tools/run_doctor.png +0 -0
- package/assets/tools/send_wechat.png +0 -0
- package/assets/tools/set_plan_steps.png +0 -0
- package/assets/tools/subagent.png +0 -0
- package/assets/tools/todo.png +0 -0
- package/assets/tools/turn-rule.png +0 -0
- package/assets/tools/user-message.png +0 -0
- package/assets/tools/watch.png +0 -0
- package/assets/tools/web_fetch.png +0 -0
- package/assets/tools/web_search.png +0 -0
- package/assets/tools/write.png +0 -0
- package/assets/tools/write_plan.png +0 -0
- package/extensions/bytefly/README.md +306 -68
- package/extensions/bytefly/block/component.ts +282 -0
- package/extensions/bytefly/block/config.ts +24 -0
- package/extensions/bytefly/block/fallback.ts +120 -0
- package/extensions/bytefly/block/register.ts +164 -0
- package/extensions/bytefly/chrome.ts +97 -0
- package/extensions/bytefly/doctor/format.ts +36 -10
- package/extensions/bytefly/doctor/tools.ts +10 -6
- package/extensions/bytefly/footer/config.ts +1 -1
- package/extensions/bytefly/footer/render/format.ts +5 -18
- package/extensions/bytefly/footer/render/layout.ts +2 -1
- package/extensions/bytefly/footer/render/segments.ts +51 -78
- package/extensions/bytefly/header/component.ts +49 -21
- package/extensions/bytefly/header/config.ts +28 -21
- package/extensions/bytefly/header/register.ts +6 -1
- package/extensions/bytefly/index.ts +32 -12
- package/extensions/bytefly/message/config.ts +15 -0
- package/extensions/bytefly/message/format.ts +42 -0
- package/extensions/bytefly/message/register.ts +15 -0
- package/extensions/bytefly/notice/component.ts +107 -0
- package/extensions/bytefly/notice/config.ts +41 -0
- package/extensions/bytefly/notice/register.ts +27 -0
- package/extensions/bytefly/pad.ts +42 -0
- package/extensions/bytefly/panel/commands.ts +69 -35
- package/extensions/bytefly/panel/format.ts +8 -8
- package/extensions/bytefly/panel/tui.ts +45 -70
- package/extensions/bytefly/separator/component.ts +2 -1
- package/extensions/bytefly/separator/config.ts +16 -8
- package/extensions/bytefly/separator/format.ts +18 -38
- package/extensions/bytefly/separator/register.ts +3 -2
- package/extensions/bytefly/separator/types.ts +0 -10
- package/extensions/bytefly/working/config.ts +20 -0
- package/extensions/bytefly/working/format.ts +25 -0
- package/extensions/bytefly/working/register.ts +88 -0
- package/extensions/document/README.md +12 -5
- package/extensions/document/paging.ts +10 -10
- package/extensions/document/render.ts +17 -16
- package/extensions/document/tool.ts +1 -1
- package/extensions/file-browse/README.md +54 -10
- package/extensions/file-browse/client.ts +110 -2
- package/extensions/file-browse/config.ts +12 -0
- package/extensions/file-browse/diff.ts +187 -0
- package/extensions/file-browse/git.ts +180 -8
- package/extensions/file-browse/html.ts +401 -25
- package/extensions/file-browse/index.ts +15 -4
- package/extensions/file-browse/markdown.ts +33 -0
- package/extensions/file-browse/router.ts +94 -2
- package/extensions/file-browse/server.ts +4 -1
- package/extensions/file-open/README.md +6 -0
- package/extensions/goal/README.md +16 -10
- package/extensions/goal/format.ts +13 -25
- package/extensions/goal/tools.ts +11 -22
- package/extensions/goal/tui.ts +12 -40
- package/extensions/job/README.md +22 -13
- package/extensions/job/format.ts +36 -13
- package/extensions/job/index.ts +26 -21
- package/extensions/job/tools.ts +15 -12
- package/extensions/job/tui.ts +148 -222
- package/extensions/job/ui.ts +24 -49
- package/extensions/memory/README.md +7 -1
- package/extensions/memory/format.ts +5 -3
- package/extensions/memory/tools.ts +4 -3
- package/extensions/memory/tui.ts +32 -36
- package/extensions/plan/README.md +86 -36
- package/extensions/plan/blocks.ts +44 -2
- package/extensions/plan/feedback.ts +20 -5
- package/extensions/plan/index.ts +1 -1
- package/extensions/plan/runtime.ts +3 -2
- package/extensions/plan/tools.ts +43 -27
- package/extensions/plan/tui.ts +21 -27
- package/extensions/plan/web-client.ts +386 -40
- package/extensions/plan/web-page.ts +138 -33
- package/extensions/plan/web-router.ts +46 -13
- package/extensions/plan/web.ts +63 -12
- package/extensions/question/README.md +14 -2
- package/extensions/question/answers.ts +25 -18
- package/extensions/question/tools.ts +22 -16
- package/extensions/question/tui.ts +132 -76
- package/extensions/rewind/README.md +3 -1
- package/extensions/rewind/format.ts +35 -2
- package/extensions/rewind/index.ts +3 -1
- package/extensions/rewind/rewind-tui.ts +66 -62
- package/extensions/rewind/snapshot-run.ts +1 -1
- package/extensions/rewind/status.ts +3 -2
- package/extensions/subagent/README.md +6 -0
- package/extensions/subagent/index.ts +1 -1
- package/extensions/subagent/render.ts +108 -66
- package/extensions/todo/README.md +20 -13
- package/extensions/todo/format.ts +47 -34
- package/extensions/todo/tools.ts +6 -4
- package/extensions/todo/tui.ts +46 -26
- package/extensions/watch/README.md +16 -8
- package/extensions/watch/format.ts +33 -13
- package/extensions/watch/index.ts +29 -24
- package/extensions/watch/tools.ts +16 -9
- package/extensions/watch/tui.ts +142 -196
- package/extensions/watch/ui.ts +24 -46
- package/extensions/web-access/README.md +16 -7
- package/extensions/web-access/fetch/tool.ts +12 -11
- package/extensions/web-access/search/tool.ts +16 -13
- package/extensions/wechat/README.md +8 -2
- package/extensions/wechat/index.ts +4 -3
- package/extensions/wechat/login-screen.ts +8 -5
- package/extensions/wechat/status-screen.ts +41 -22
- package/extensions/wechat/tools.ts +6 -5
- package/extensions/worktree/README.md +6 -0
- package/extensions/worktree/enter.ts +1 -1
- package/extensions/worktree/index.ts +1 -1
- package/extensions/worktree/runtime.ts +1 -1
- package/lib/README.md +11 -7
- package/lib/format.ts +17 -0
- package/lib/notice.ts +87 -0
- package/lib/requirements.ts +2 -2
- package/lib/{tui.ts → tui/chrome.ts} +17 -34
- package/lib/tui/columns.ts +96 -0
- package/lib/{list-cursor.ts → tui/cursor.ts} +58 -4
- package/lib/tui/gauge.ts +78 -0
- package/lib/{ui.ts → tui/glyphs.ts} +10 -11
- package/lib/tui/indent.ts +166 -0
- package/lib/tui/index.ts +27 -0
- package/lib/tui/line-pane.ts +173 -0
- package/lib/tui/rows.ts +143 -0
- package/lib/tui/rules.ts +94 -0
- package/lib/tui/status-controller.ts +107 -0
- package/lib/tui/tokens.ts +72 -0
- package/lib/web/base.ts +2 -1
- package/lib/web/components.ts +3 -1
- package/lib/web/layout.ts +5 -1
- package/package.json +7 -3
- package/themes/bytefly-dark.json +7 -8
- package/themes/bytefly-light.json +10 -11
- package/assets/bytefly-chrome.png +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
# bytefly — the TUI header, footer, turn rule, extension screen, and notifications
|
|
1
|
+
# bytefly — the TUI header, footer, user-message marker, turn rule, extension screen, and notifications
|
|
2
2
|
|
|
3
3
|
`bytefly` owns the terminal chrome, configuration, and diagnostics surfaces
|
|
4
4
|
this package adds: one themed startup header whose two-tone nameplate carries
|
|
5
5
|
the agent and chrome identities, one compact, colorful, width-adaptive two-line
|
|
6
|
-
footer, a
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
footer, a two-row `You` nameplate that opens each user message, a labeled rule that
|
|
7
|
+
marks each completed turn in the transcript, one keyboard-driven screen that
|
|
8
|
+
lists every resolved Pi extension with its enable checkbox and its health, and
|
|
9
|
+
an opt-in notify capability that raises an OS notification when a run finishes,
|
|
10
|
+
a job finishes, or the agent asks for input.
|
|
10
11
|
DeepSeek is priced from the provider's published yuan rates and peak tariff by
|
|
11
12
|
default, and any other model can be priced from your own rates when Pi's catalog
|
|
12
13
|
does not match what a provider actually charges.
|
|
@@ -17,53 +18,63 @@ pi -e . # load the whole @gavin-hu/my-pi-agent pac
|
|
|
17
18
|
pi install ./ # install the package
|
|
18
19
|
```
|
|
19
20
|
|
|
21
|
+
## Tool rendering
|
|
22
|
+
|
|
23
|
+
How the `run_doctor` call and its result look in the transcript — the call line as a headline and the body indented under it:
|
|
24
|
+
|
|
25
|
+
<img src="../../assets/tools/run_doctor.png" alt="The run_doctor tool's result: the call line and an indented body with the doctor headline and the missing and degraded findings" width="100%">
|
|
26
|
+
|
|
20
27
|
## What it does
|
|
21
28
|
|
|
22
|
-
The extension owns
|
|
23
|
-
between completed turns, the
|
|
29
|
+
The extension owns nine surfaces: the startup header, the footer, the
|
|
30
|
+
user-message marker, the rule between completed turns, the notice block for
|
|
31
|
+
shared transcript notices, the tool-block frame, the live working counter, the
|
|
32
|
+
extension screen, and notifications.
|
|
24
33
|
|
|
25
34
|
**Header.** A nameplate: a two-tone half-block mark from the active theme's
|
|
26
|
-
`accent` / `
|
|
27
|
-
chrome identity (`enhanced by bytefly` and the package version), a
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
two-tone `Pi` wordmark.
|
|
35
|
+
`accent` / `warn` roles, the agent identity (`Pi`, bold, and its version), the
|
|
36
|
+
chrome identity (`enhanced by bytefly` and the package version), a signature
|
|
37
|
+
rule whose `accent` lead sits under the mark, and a grouped help block. The help
|
|
38
|
+
keys resolve live from Pi's keybindings, so a rebound key shows the user's
|
|
39
|
+
chord; the identity and help text are `meta` / `faint` so the mark keeps the
|
|
40
|
+
eye. It is installed only in interactive (`tui`) sessions, and on terminals that
|
|
41
|
+
cannot render half blocks the mark falls back to a two-tone `Pi` wordmark.
|
|
33
42
|
|
|
34
43
|
```
|
|
35
44
|
█▀█ Pi v1.2.0
|
|
36
|
-
█▀ █ enhanced by bytefly v0.
|
|
45
|
+
█▀ █ enhanced by bytefly v0.8.1
|
|
37
46
|
─────────────────────────────────────────────────
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
escape to interrupt · ctrl+c to clear · ctrl+d to exit (empty)
|
|
48
|
+
ctrl+o to expand tools · ctrl+t to expand thinking · ctrl+l to select model
|
|
49
|
+
/ commands · ! bash · !! bash (no context) · /bytefly extensions
|
|
41
50
|
```
|
|
42
51
|
|
|
43
52
|
As the terminal narrows, the identity sheds the chrome version, then the chrome
|
|
44
53
|
line, then the agent name, and the help rows drop whole keys, so nothing wraps or
|
|
45
|
-
clips mid-word. The
|
|
46
|
-
|
|
54
|
+
clips mid-word. The nameplate sits on the transcript margin, which follows Pi's
|
|
55
|
+
`outputPad` (the value the tool frame and the notice use too), and the help hangs
|
|
56
|
+
one body indent inside it. The mark, tokens, identity, and grouped help are tuned
|
|
57
|
+
in [`header/config.ts`](./header/config.ts).
|
|
47
58
|
|
|
48
59
|
**Footer.** Two lines, each with a left and right zone:
|
|
49
60
|
|
|
50
61
|
- **Line 1 — identity:** `pwd` and the session name on the left; git state
|
|
51
62
|
(`⎇ branch · ⑂ worktree`) and the `◉` browse chip on the right.
|
|
52
63
|
- **Line 2 — resources:** the context gauge and usage meters on the left, the
|
|
53
|
-
mode/alert slot (`⋮ plan`) trailing after a
|
|
64
|
+
mode/alert slot (`⋮ plan`) trailing after a `╎` when present; the model and
|
|
54
65
|
thinking level on the right. The gauge is anchored at column 0, so `%` is
|
|
55
66
|
always in the same place.
|
|
56
67
|
|
|
57
68
|
```
|
|
58
69
|
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
59
|
-
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87%
|
|
70
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↑42k ↓8.0k · R96k CH 87% ╎ ⋮ plan opus-4.5 · high
|
|
60
71
|
```
|
|
61
72
|
|
|
62
73
|
(The examples show the default `¥` symbol. For a model the built-in table does
|
|
63
74
|
not cover, the number stays Pi's recorded USD amount — see the currency note
|
|
64
75
|
under [Configuration](#configuration).)
|
|
65
76
|
|
|
66
|
-
With no plan mode there is no mode slot, so the
|
|
77
|
+
With no plan mode there is no mode slot, so the `╎` is omitted:
|
|
67
78
|
|
|
68
79
|
```
|
|
69
80
|
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
@@ -76,7 +87,7 @@ fits, rather than collapsing to a bare glyph:
|
|
|
76
87
|
|
|
77
88
|
```
|
|
78
89
|
~/repo/project ⎇ main · ⑂ smoke
|
|
79
|
-
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31
|
|
90
|
+
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31 ╎ ⋮ plan opus-4.5 · high
|
|
80
91
|
```
|
|
81
92
|
|
|
82
93
|
```
|
|
@@ -88,7 +99,7 @@ With a named session, the name follows the path and truncates before it drops:
|
|
|
88
99
|
|
|
89
100
|
```
|
|
90
101
|
~/repo/project · feature-refac… ⎇ main
|
|
91
|
-
▰▰▰▰▰▰▱▱▱▱ 62%
|
|
102
|
+
▰▰▰▰▰▰▱▱▱▱ 62% ╎ ⋮ plan opus-4.5
|
|
92
103
|
```
|
|
93
104
|
|
|
94
105
|
Zero-value meters are omitted, so a fresh session shows only `?/window` instead
|
|
@@ -107,11 +118,122 @@ rates and peak tariff built into [`footer/price/config.ts`](./footer/price/confi
|
|
|
107
118
|
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥2.50 · ↑42k ↓8.0k · R96k CH 87% opus-4.5 · high
|
|
108
119
|
```
|
|
109
120
|
|
|
121
|
+
**User message.** Every user message opens with a two-row `You` nameplate —
|
|
122
|
+
the label over a rule that spans the width — above the message:
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
You
|
|
126
|
+
────────────────────────────────────
|
|
127
|
+
|
|
128
|
+
the message the user typed
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
It is always on in interactive sessions and has no config file. Pi renders a
|
|
132
|
+
user message as Markdown and owns its colors, so bytefly's only lever is a
|
|
133
|
+
`registerMarkdownTransformer`: the nameplate is a single level-2 heading whose
|
|
134
|
+
text is padded so the rule wraps onto the second row, and both rows carry the
|
|
135
|
+
accent because the themes point `mdHeading` at it. The block carries no fill —
|
|
136
|
+
the shipped themes set `userMessageBg` to the terminal default, so it reads like
|
|
137
|
+
the tool blocks. The nameplate is separated from the message by a blank line, so
|
|
138
|
+
the message's own Markdown (a fence, a list, a second paragraph) parses exactly
|
|
139
|
+
as it would without it, and a soft wrap of one long line stays at the margin
|
|
140
|
+
because the renderer wraps it, not bytefly. The label and the rule are tuned
|
|
141
|
+
in [`message/config.ts`](./message/config.ts).
|
|
142
|
+
|
|
143
|
+
**Working timer.** Pi's working row shows a static `Working`, so a long run
|
|
144
|
+
reads the same as a short one. While the row is up, bytefly advances its
|
|
145
|
+
message once a second and hands it back to Pi when the row comes down:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
Working… 12s
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The count is tied to the row's visibility: it starts on `turn_start`, the event
|
|
152
|
+
the host shows the working indicator on, and stops on `agent_end`, where the
|
|
153
|
+
host clears it, then again on `session_shutdown`. Turns inside one run do not
|
|
154
|
+
restart it — the host keeps the same row up across turns — so the count covers
|
|
155
|
+
the whole run, tool calls included. A retry is a new run, so the count restarts
|
|
156
|
+
when its row reappears. The word and the interval are tuned in
|
|
157
|
+
[`working/config.ts`](./working/config.ts).
|
|
158
|
+
|
|
110
159
|
**Turn separator.** After each completed turn the extension appends an inert
|
|
111
160
|
entry and draws a centered `╌╌╌ turn N ╌╌╌` rule across the transcript; see
|
|
112
161
|
[Turn separator](#turn-separator). No config file is needed and there is no
|
|
113
162
|
command.
|
|
114
163
|
|
|
164
|
+
**Notices.** Any extension in the package can post a transcript notice under the
|
|
165
|
+
shared `my-pi-agent/notice` type; bytefly draws it at the transcript's margin —
|
|
166
|
+
a `source · title` headline at the margin, then rail-led rows, each with its own
|
|
167
|
+
severity glyph:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
job · 2 background jobs finished
|
|
171
|
+
╎ ✓ j1 build · exit 0
|
|
172
|
+
╎ ✕ j2 test · exit 1
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The rail is painted by the notice's worst severity, so a failure reads red at the
|
|
176
|
+
edge like an errored tool result.
|
|
177
|
+
|
|
178
|
+
`job` and `watch` post one when a background job finishes or a watched line
|
|
179
|
+
matches, so the report the model reads is visible too. The type and the
|
|
180
|
+
`NoticeDetails` shape are the shared contract in
|
|
181
|
+
[`lib/notice.ts`](../../lib/notice.ts), and the severity glyphs and item cap
|
|
182
|
+
are tuned in [`notice/config.ts`](./notice/config.ts). Every field is sanitized
|
|
183
|
+
and clipped at the boundary, and a message without `details` keeps Pi's default
|
|
184
|
+
custom-message box.
|
|
185
|
+
|
|
186
|
+
**Tool blocks.** Every tool block leads with the tool's own call line as the
|
|
187
|
+
headline — the tool name in the theme's tool-title colour — and its result body
|
|
188
|
+
sits two columns in directly beneath it, led by the transcript rail, instead of
|
|
189
|
+
Pi's filled status background:
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
read src/app.ts
|
|
193
|
+
╎ const answer = 42;
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The two tools that mutate a file, `edit` and `write`, carry their result on the
|
|
197
|
+
call body — the edit diff, the written file content — so that body is railed
|
|
198
|
+
like any other result. There is no status band: the diff's own red/green line
|
|
199
|
+
colours, with the changed words in reverse video, and the `edit` / `write`
|
|
200
|
+
headline are what mark a file change.
|
|
201
|
+
|
|
202
|
+
A `registerToolRenderer` resolver switches the row to `renderShell: "self"`,
|
|
203
|
+
leaves the call's own first line as the headline, and indents the rest of the
|
|
204
|
+
call and the whole result under it. A shell call's `$` / `>` prompt becomes the
|
|
205
|
+
tool name and the command is repainted in the body colour, and a primary subject
|
|
206
|
+
(a path, URL, query, pattern) is demoted to the body colour too, so the name is
|
|
207
|
+
the call line's only accent (`bash bun run check`, `read src/app.ts`). The
|
|
208
|
+
tool's own
|
|
209
|
+
`renderCall`/`renderResult` are passed through, so syntax highlighting, diffs,
|
|
210
|
+
previews, and truncation notices are unchanged — only the frame is bytefly's.
|
|
211
|
+
The body carries the transcript rail, painted by status (a running result takes
|
|
212
|
+
the accent, a failure red, a finished one neutral) and drawn with the glyph from
|
|
213
|
+
the `chrome.rail` setting. A result frame is always railed; a call frame is railed
|
|
214
|
+
only for `edit` and `write`, whose call body carries the result — every other
|
|
215
|
+
call's headline and continuation lines stay plain-indented. A call line that
|
|
216
|
+
does not fit wraps, and Pi drops the tool name onto its own line when the
|
|
217
|
+
subject it carries (a long path) is one unbreakable token; those continuation
|
|
218
|
+
lines are still the call, so they stay unrailed and lose the accent too, and the
|
|
219
|
+
rail begins with the result underneath. A tool with
|
|
220
|
+
no renderer of its own is framed around a generic call/result fallback, whose
|
|
221
|
+
call line reads like a built-in — the leading string argument bare, the rest as
|
|
222
|
+
trailing options (`open_path src/app.ts`) — rather than dumping raw `key=value`
|
|
223
|
+
pairs. A tool that draws its own shell (`edit`) is framed too:
|
|
224
|
+
`renderShell: "self"` only tells Pi not to draw its box around the renderer, so
|
|
225
|
+
its diff would otherwise sit at the wrong indent; the frame drops the blank
|
|
226
|
+
edges its own `Box` pads itself with, and hands it a theme whose `bg` is inert so
|
|
227
|
+
it never paints a band the rest of the transcript does not have.
|
|
228
|
+
|
|
229
|
+
The call line is one colour grammar, shared with Pi's built-ins: the tool name is
|
|
230
|
+
`toolTitle` and bold and is the line's only accent; a primary subject (a query, a
|
|
231
|
+
URL, a path, a status) reads in the body role (`label`), counts and summaries are
|
|
232
|
+
`muted`, trailing options are `dim`, and the result body is `toolOutput`. The
|
|
233
|
+
shipped themes point `toolTitle` at the accent and `label` at the body colour, so
|
|
234
|
+
the name is the call line's one accent and the subject follows as body text; a
|
|
235
|
+
theme that maps `toolTitle` elsewhere is respected rather than overridden.
|
|
236
|
+
|
|
115
237
|
**Extension screen.** `/bytefly [extension] [refresh]` opens a keyboard-driven
|
|
116
238
|
dock list of every Pi extension the session resolves — across personal settings
|
|
117
239
|
and, when trusted, the project — one row per extension with its enable checkbox
|
|
@@ -133,19 +255,18 @@ the platform notifier (`osascript`, `notify-send`); see
|
|
|
133
255
|
| Command | What it does |
|
|
134
256
|
|---|---|
|
|
135
257
|
| `/bytefly [extension] [refresh]` | Open the extension screen. In `tui` it mounts a docked list; every other mode prints the grouped listing, or one extension's full findings when named. |
|
|
136
|
-
| `/
|
|
137
|
-
| `/doctor [extension] [refresh]` | Alias for `/bytefly`: the same screen and the same handler. |
|
|
258
|
+
| `/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. |
|
|
138
259
|
|
|
139
|
-
Tab completes extension names and `refresh
|
|
260
|
+
Tab completes `doctor`, extension names, and `refresh`.
|
|
140
261
|
|
|
141
262
|
## Behaviour by mode
|
|
142
263
|
|
|
143
264
|
The header, footer, and turn rule are installed only in interactive (`tui`)
|
|
144
265
|
sessions and are always on; every mode loads the extension, and non-TUI modes
|
|
145
266
|
change nothing. The screen is available in every mode: in `tui`, `/bytefly` and
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
267
|
+
`/bytefly doctor` mount the docked screen, while RPC, JSON, and print modes
|
|
268
|
+
print the grouped listing with a per-row health suffix and the headline, or that
|
|
269
|
+
extension's full findings when one is named. The
|
|
149
270
|
proactive session-start warning is skipped when there is no UI. Notify runs in
|
|
150
271
|
every mode and picks its method from the environment; the OSC methods need a
|
|
151
272
|
TTY, so a print/JSON/RPC run gets an OS-level notification or none.
|
|
@@ -153,14 +274,19 @@ TTY, so a print/JSON/RPC run gets an OS-level notification or none.
|
|
|
153
274
|
## Configuration
|
|
154
275
|
|
|
155
276
|
The header is tuned in [`header/config.ts`](./header/config.ts) — the mark and
|
|
156
|
-
identity theme tokens, the
|
|
157
|
-
|
|
277
|
+
identity theme tokens, the tagline, and the grouped help entries (each naming a
|
|
278
|
+
Pi keybinding resolved live or a raw command prefix). The footer's
|
|
158
279
|
content and layout are tuned in [`footer/config.ts`](./footer/config.ts) —
|
|
159
280
|
thresholds, gauge
|
|
160
281
|
glyphs and widths, separators, icons, and status keys. The turn separator has no
|
|
161
282
|
JSON either: its glyph, label prefix, padding, and colors are tuned in
|
|
162
283
|
[`separator/config.ts`](./separator/config.ts).
|
|
163
284
|
|
|
285
|
+
The transcript rail's glyph is the one chrome value that is JSON-configurable:
|
|
286
|
+
the `chrome` section's `rail` key (default `╎`) picks a single-column rail glyph,
|
|
287
|
+
read at `session_start`/`session_tree`. Everything else about the chrome is tuned
|
|
288
|
+
in code.
|
|
289
|
+
|
|
164
290
|
Everything JSON-configurable lives in `bytefly.json`, one shared document with a
|
|
165
291
|
top-level section per extension (see [Configuration](../../docs/configuration.md)).
|
|
166
292
|
It is read from the global document, then `<cwd>/.pi/bytefly.json`. The old
|
|
@@ -354,7 +480,7 @@ its server runs, and shows the two-tone `◉ <port>` (green glyph, accent port).
|
|
|
354
480
|
The trailing slot shows plan-style alerts when present and is omitted otherwise;
|
|
355
481
|
a plan chip's trailing plan file name is dropped, so the slot reads `⋮ plan`
|
|
356
482
|
even though the built-in footer keeps the name. An alert (a failed job) sorts to
|
|
357
|
-
the front of the slot. The slot trails the meters after a
|
|
483
|
+
the front of the slot. The slot trails the meters after a `╎`, so the context
|
|
358
484
|
gauge always starts the line. It keeps each extension's own colour when it
|
|
359
485
|
compacts, and it is droppable: a tight bar drops the slot rather than truncating
|
|
360
486
|
the model, which sits at the end of the line.
|
|
@@ -394,10 +520,13 @@ it:
|
|
|
394
520
|
extension Pi resolves for the session, so the list matches what actually loads.
|
|
395
521
|
It merges the former extensions picker and doctor report into one row per
|
|
396
522
|
extension: the picker's enable checkbox and label, the doctor's worst-severity
|
|
397
|
-
glyph and summary.
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
523
|
+
glyph and summary. The screen is drawn from the design system: a label-first
|
|
524
|
+
`bytefly ────` title rule, one row grammar (`❯ ◼ ✓ name … summary`), and the
|
|
525
|
+
shared `◼` / `◻` checkbox. `/bytefly doctor [extension] [refresh]` selects the doctor
|
|
526
|
+
report, the same text the `run_doctor` tool returns; in `tui` it opens the same
|
|
527
|
+
screen. `[extension]` narrows either surface to one extension and `refresh`
|
|
528
|
+
re-probes the doctor before it opens. Tab completes `doctor`, extension names,
|
|
529
|
+
and `refresh`.
|
|
401
530
|
|
|
402
531
|
The screen reuses Pi's own settings and package resolution (`SettingsManager`
|
|
403
532
|
plus `DefaultPackageManager` with `onMissing: "skip"`), so opening it never
|
|
@@ -408,7 +537,7 @@ installs or fetches a package.
|
|
|
408
537
|
- Omits `bytefly`'s own entrypoint from the picker groups, so the tool that
|
|
409
538
|
manages the list is never a selectable row; its doctor report still appears in
|
|
410
539
|
the trailing `Not resolved` group.
|
|
411
|
-
- Shows whether each one is enabled (
|
|
540
|
+
- Shows whether each one is enabled (`◼`) or disabled (`◻`).
|
|
412
541
|
- Shows the worst severity for a reported extension (`✓` ok, `!` degraded, `✕`
|
|
413
542
|
missing, `∅` disabled) and its summary; an extension with no doctor report
|
|
414
543
|
leaves the glyph column and the summary blank rather than claiming `ok`.
|
|
@@ -524,6 +653,9 @@ control-free line before it reaches an escape sequence or a shell argument.
|
|
|
524
653
|
|
|
525
654
|
## Limitations
|
|
526
655
|
|
|
656
|
+
- **`doctor` is a reserved first argument.** `/bytefly doctor` always selects the
|
|
657
|
+
report, so an extension literally named `doctor` cannot be narrowed to by
|
|
658
|
+
name.
|
|
527
659
|
- **The picker manages only the `extensions` resource type.** Skills, prompts,
|
|
528
660
|
and themes are handled by Pi's own `pi config`.
|
|
529
661
|
- **Built-in extensions are not listed** (`builtin:mcp`, `builtin:codemode`, …):
|
|
@@ -567,6 +699,11 @@ control-free line before it reaches an escape sequence or a shell argument.
|
|
|
567
699
|
- **An explicit `method` is honored blindly.** Point `method` at a notifier the
|
|
568
700
|
host lacks (or an OSC method off a TTY) and the notification is silently
|
|
569
701
|
dropped; only `auto` inspects the environment.
|
|
702
|
+
- **The working counter is one global row.** `setWorkingMessage` drives the
|
|
703
|
+
single working row, so bytefly and any other extension setting it race — last
|
|
704
|
+
writer wins — and the message is reset to Pi's default at `agent_end`. If the
|
|
705
|
+
row is hidden (`ctx.ui.setWorkingVisible(false)`) the counter has no surface,
|
|
706
|
+
and a reload mid-run does not resume it until the next turn.
|
|
570
707
|
|
|
571
708
|
## Non-goals
|
|
572
709
|
|
|
@@ -590,6 +727,9 @@ control-free line before it reaches an escape sequence or a shell argument.
|
|
|
590
727
|
whole surface.
|
|
591
728
|
- No sound, action buttons, notification history, or de-duplication; a
|
|
592
729
|
notification is a fire-and-forget message, not an inbox.
|
|
730
|
+
- No frozen per-run working duration: the counter is live and is handed back to
|
|
731
|
+
Pi when the working row comes down, because the extension API exposes no hook
|
|
732
|
+
to keep a finished run's total.
|
|
593
733
|
|
|
594
734
|
The built-in footer's `(auto)` auto-compact indicator and `(sub)`
|
|
595
735
|
subscription-cost marker are not reachable from `ExtensionContext` (there is no
|
|
@@ -600,35 +740,100 @@ rather than showing a wrong value.
|
|
|
600
740
|
|
|
601
741
|
| Integration point | Details |
|
|
602
742
|
|---|---|
|
|
603
|
-
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"`. 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. |
|
|
743
|
+
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"`. 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. |
|
|
604
744
|
| Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
|
|
605
|
-
|
|
|
745
|
+
| 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. |
|
|
746
|
+
| Notice | `registerMessageRenderer(NOTICE_TYPE)` draws every shared transcript notice at the margin from its `details`; the headline stays at the margin and its rows hang from the transcript rail, painted by the notice's worst severity, whose glyph comes from the shared `RailSource`. The type and shape come from `lib/notice.ts`. A message without `details` falls back to Pi's default custom-message box. |
|
|
747
|
+
| Tool blocks | `registerToolRenderer` returns, for every tool, `renderShell: "self"`; `renderCall` leaves the tool's own first line as the block's headline (a shell prompt shown as the tool name, its command repainted in the body colour, and a primary subject demoted to the body colour) and indents the rest of the call two columns under it, `renderResult` indents its body the same and leads it with the status-coloured rail, and each wraps the tool's own renderer (or a generic fallback). `edit` and `write` carry their result on the call body, so that body is railed too. |
|
|
748
|
+
| Screen command | `pi.registerCommand("bytefly")` takes `[doctor] [extension] [refresh]`: `tui` mounts a dock screen via `ctx.ui.custom()` with the rails suppressed; other modes print through `ctx.ui.notify()` — the grouped listing, or `run_doctor`'s report for `doctor`. Tab completes `doctor`, extension names, and `refresh`. |
|
|
606
749
|
| Turn separator | `registerEntryRenderer("bytefly-separator")` draws each rule; `agent_settled` appends `pi.appendEntry("bytefly-separator", { turn })` in `tui` mode only. |
|
|
750
|
+
| Working timer | `turn_start` starts a 1s tick that drives `ctx.ui.setWorkingMessage("Working… Ns")` in `tui` mode; `agent_end` restores Pi's default and cancels the tick (also on `session_shutdown`). No config file and no stored state. |
|
|
607
751
|
| 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. |
|
|
608
752
|
| Picker discovery | `SettingsManager.create(...)` plus `DefaultPackageManager.resolve({ onMissing: "skip" })`, both public exports; both views drop `bytefly`'s own entrypoint. |
|
|
609
753
|
| Picker writes | `SettingsManager` setters (`setExtensionPaths`, `setPackages`, `setProjectExtensionPaths`, `setProjectPackages`) then `flush()`; `ctx.reload()` after the screen closes when changes are pending. |
|
|
610
754
|
| Doctor tool | `pi.registerTool("run_doctor")`, read-only (`readOnlyHint: true`), `exposure: "direct"`, active by default, 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. |
|
|
611
755
|
| Doctor probes | `run_doctor` and the screen share the session cache created by `registerDoctor`; `/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. |
|
|
612
756
|
| 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. |
|
|
613
|
-
| 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),
|
|
757
|
+
| 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. |
|
|
614
758
|
| Data sources | `footerData.getGitBranch()`, `footerData.getAvailableProviderCount()`, `ctx.getContextUsage()`, `ctx.sessionManager.getEntries()`, `ctx.sessionManager.getSessionName()`, `ctx.model`; subscribes to `footerData.onBranchChange` to repaint. |
|
|
615
759
|
| State storage | None besides the inert separator entries. The footer reads session entries and the price config (a memoized scan) and writes no tool-result `details`; it appends `bytefly-separator` entries excluded from LLM context. The screen derives its view from the picker runtime and the current reports and persists only through `settings.json`. 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. |
|
|
616
|
-
| Lifecycle | `session_start` installs the header and footer, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on, and loads the notify config and subscribes to the job bus; `session_tree` reinstalls the header and footer; `session_shutdown` restores Pi's built-in header and footer, disposes the branch subscription, drops doctor's cached findings, and drops the notify bus subscription. |
|
|
760
|
+
| Lifecycle | `session_start` installs the header and footer, loads the chrome rail glyph, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on, and loads the notify config and subscribes to the job bus; `session_tree` reinstalls the header and footer and reloads the rail; `session_shutdown` restores Pi's built-in header and footer, disposes the branch subscription, drops doctor's cached findings, and drops the notify bus subscription. |
|
|
617
761
|
|
|
618
762
|
## Design notes
|
|
619
763
|
|
|
764
|
+
- **One kit, one look.** Every bytefly surface is drawn from the package's
|
|
765
|
+
`lib/tui/` design system: a role is resolved by the active theme, a rule comes
|
|
766
|
+
from `rules.ts`, a list row from `rows.ts`, a meter from `gauge.ts`, and a
|
|
767
|
+
width from `columns.ts`. Nothing in bytefly names a literal color, and a
|
|
768
|
+
theme swap re-skins the whole chrome.
|
|
769
|
+
- **The user message is shaped, not painted.** Pi renders a user message as
|
|
770
|
+
Markdown and owns its colors, so bytefly's only lever is a Markdown
|
|
771
|
+
transformer: the two-row nameplate is one level-2 heading whose text is padded
|
|
772
|
+
to the width so the rule wraps below the label, and both rows take the accent
|
|
773
|
+
from the theme's `mdHeading`, because no extension API can color it directly.
|
|
774
|
+
Markdown has no multi-line heading and Pi inserts a blank line after a
|
|
775
|
+
heading block, so a single wrapped heading is the only way to keep the two
|
|
776
|
+
rows adjacent and in the accent. The block has no fill: the shipped themes set
|
|
777
|
+
`userMessageBg` to the terminal default, so it matches the tool blocks. The
|
|
778
|
+
nameplate is separated from the message by a blank line, so the message's own
|
|
779
|
+
Markdown parses unchanged and a soft wrap stays at the margin; hard-wrapping
|
|
780
|
+
Markdown here would corrupt a break inside an inline construct.
|
|
781
|
+
- **A notice is one shared contract, not a foreign type.** Pi resolves a
|
|
782
|
+
custom-message renderer by exact type with no wildcard, so `lib/notice.ts`
|
|
783
|
+
owns the type and the `NoticeDetails` shape: a producer states model text and
|
|
784
|
+
renderer details once, and bytefly owns only the look. One type for every
|
|
785
|
+
producer also lets `job` and `watch` share one prune
|
|
786
|
+
(`pruneStaleNotices`) keyed on `details.source`, so neither drops the other's
|
|
787
|
+
note from context.
|
|
788
|
+
- **The frame delegates; it does not re-render.** Pi resolves tool renderers
|
|
789
|
+
through the extension chain, and the resolved object is the definition the row
|
|
790
|
+
reads, so a resolver can override `renderShell` and wrap `next()`'s
|
|
791
|
+
`renderCall`/`renderResult`. bytefly replaces only the frame — Pi's filled
|
|
792
|
+
status box for an indent — and keeps every built-in's diff, syntax
|
|
793
|
+
highlighting, and truncation. The call and result are sibling components with
|
|
794
|
+
no spacer between them, so the call's headline and the result read as one
|
|
795
|
+
block; the result body hangs from the rail, and `edit`/`write` rail their call
|
|
796
|
+
body because it carries the result, except for the lines of a call line that
|
|
797
|
+
wrapped onto the body — a 121-column path under a bare `edit` is still the
|
|
798
|
+
call, not diff content, and the rail starts at the diff. A tool that renders
|
|
799
|
+
its own shell (`edit`)
|
|
800
|
+
is framed too: its blank edge lines are trimmed so the body starts under the
|
|
801
|
+
call, and it is handed a theme whose `bg` is inert so it paints no band. Each base renderer is handed its own
|
|
802
|
+
previous component (tracked in the row's `state`), never the frame: Pi gives a
|
|
803
|
+
renderer the component it returned last time, and a built-in calls `setText` on
|
|
804
|
+
it, so handing back the frame would break it. A base renderer that throws is
|
|
805
|
+
caught here too, and the frame falls back to its own call/result line at the
|
|
806
|
+
frame's pad; letting the throw reach Pi would swap in Pi's generic call line,
|
|
807
|
+
which sits a column to the left of the framed one.
|
|
808
|
+
- **One frame, one left edge.** Every transcript block that is not prose shares
|
|
809
|
+
the same frame (`lib/tui/indent.ts`): a tool block, a notice, and a subagent's
|
|
810
|
+
quoted output take one indent, so they hang from one left edge instead of four,
|
|
811
|
+
and a tool result's body sits `BODY_INDENT` columns in under its headline. A
|
|
812
|
+
body and a notice row lead that body with the transcript rail, whose
|
|
813
|
+
glyph is the one configurable part (`chrome.rail`, default `╎`); a result frame
|
|
814
|
+
is always railed, and a call frame only for `edit`/`write`, whose call body
|
|
815
|
+
carries the result. Pi pads its own messages and hands the value to tool renderers
|
|
816
|
+
(`context.outputPad`) and message renderers (`options.outputPad`), but gives an
|
|
817
|
+
entry renderer none and adds its component raw, so bytefly's blocks inset
|
|
818
|
+
themselves by that pad: the tool frame and the notice take it from Pi, and the
|
|
819
|
+
turn separator reads the last value a sibling observed (`pad.ts`). Pi's setting
|
|
820
|
+
is the only knob — bytefly adds no padding of its own. The footer's group
|
|
821
|
+
separator still draws `╎` between chips — a divider, not a rail.
|
|
620
822
|
- **The header is a nameplate, not a dashboard.** Pi's built-in brand colors are
|
|
621
823
|
fixed, so the mark ignores the active theme; bytefly's header draws a two-tone
|
|
622
|
-
mark from `accent`/`
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
824
|
+
mark from the `accent`/`warn` roles, a signature rule whose accent lead sits
|
|
825
|
+
under the mark, and pairs them with the agent identity, the chrome identity,
|
|
826
|
+
and a grouped help block. It takes its margin from Pi's `outputPad`, like the
|
|
827
|
+
tool frame and the notice, and hangs the help one body indent inside it, so the
|
|
828
|
+
header follows a non-default pad instead of assuming a column. It adds no
|
|
829
|
+
session or model data — that is the footer's job — and it stays a fixed
|
|
830
|
+
four-plus rows so the startup transcript never reflows.
|
|
626
831
|
- **Two lines, four zones.** Line 1 is identity (`pwd` left, branch + worktree
|
|
627
832
|
right); line 2 is resources (meters left, model + level right). This keeps
|
|
628
833
|
"where am I / what state" separate from "how much am I burning".
|
|
629
834
|
- **The gauge is anchored at column 0.** A leading mode slot would shift the
|
|
630
835
|
context percentage left and right as plan mode came and went; trailing it
|
|
631
|
-
after a
|
|
836
|
+
after a `╎` keeps the percentage in a fixed place while the mode stays
|
|
632
837
|
visible as the meters drop.
|
|
633
838
|
- **Statuses are routed, not repeated.** The built-in footer renders every
|
|
634
839
|
`setStatus` value on its own line; the bar splits them by meaning (`worktree`
|
|
@@ -648,19 +853,23 @@ rather than showing a wrong value.
|
|
|
648
853
|
non-zero usage, so it reads full only at 100% and a small percentage never
|
|
649
854
|
disappears; unknown usage draws no gauge at all. Only at extreme widths does
|
|
650
855
|
`truncateToWidth` clip the remaining text.
|
|
651
|
-
- **Separators shrink to a single space.** Padded separators (` · `, `
|
|
856
|
+
- **Separators shrink to a single space.** Padded separators (` · `, ` ╎ `)
|
|
652
857
|
collapse to one space before `truncateToWidth` applies, so adjacent segments
|
|
653
|
-
never collide and the ellipsis never replaces a
|
|
858
|
+
never collide and the ellipsis never replaces a `╎` with nothing after it.
|
|
654
859
|
- **Statuses compact with their colour.** A themed status's compact icon form
|
|
655
860
|
reattaches its opening and closing SGR sequences around the visible text, so a
|
|
656
861
|
red `✗1` stays red instead of losing its colour exactly when the bar tightens.
|
|
657
862
|
A two-token `icon count` badge (for `rewind`: `↺ 2`) compacts to `↺2`, keeping
|
|
658
863
|
the count. The slot sorts an alert (a failed job) ahead of the modes and is
|
|
659
864
|
droppable, so it goes before the model is clipped.
|
|
660
|
-
- **Neutral by default; color means something.**
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
865
|
+
- **Neutral by default; color means something.** A tool block carries no status
|
|
866
|
+
colour except the accent tool name and the status-coloured result rail; an
|
|
867
|
+
informational notice leads with `muted`; a failure is red only where the
|
|
868
|
+
tool's own output says so, so the transcript is not a wall of green.
|
|
869
|
+
The context gauge is the other coloured surface: it stays `muted` below 70%,
|
|
870
|
+
cost is `muted`, the session and branch are `muted`, and tokens/cache/window are
|
|
871
|
+
`dim`, so yellow and red are reserved for a threshold or a failure rather than
|
|
872
|
+
always on.
|
|
664
873
|
- **Data is read fresh, except the usage scan.** The component resolves the
|
|
665
874
|
theme through a getter and reads a fresh snapshot each render. The expensive
|
|
666
875
|
part — summing token/cost totals across the session — is memoized by
|
|
@@ -722,7 +931,7 @@ rather than showing a wrong value.
|
|
|
722
931
|
reads the same command whether a tool failed or the report named it.
|
|
723
932
|
- **The doctor is quiet by default at startup.** Only `missing` findings warn,
|
|
724
933
|
only for enabled extensions, only with a UI, and only once per session;
|
|
725
|
-
`degraded` findings — including a malformed config — wait in `/doctor`, because
|
|
934
|
+
`degraded` findings — including a malformed config — wait in `/bytefly doctor`, because
|
|
726
935
|
a session that nags about an optional package is worse than one that never
|
|
727
936
|
mentions it.
|
|
728
937
|
- **Probe the real thing.** `subagent`'s requirement resolves through the same
|
|
@@ -735,15 +944,22 @@ rather than showing a wrong value.
|
|
|
735
944
|
## Files
|
|
736
945
|
|
|
737
946
|
The surfaces are folders: `header/`, `footer/` (the status bar and its price
|
|
738
|
-
calculation), `
|
|
947
|
+
calculation), `message/` (the user-message marker), `notice/` (the shared notice),
|
|
948
|
+
`block/` (the tool-block frame), `separator/`, `working/` (the live
|
|
949
|
+
elapsed counter on Pi's working row), `panel/` (the
|
|
950
|
+
unified screen and its merged model),
|
|
739
951
|
`picker/` (discovery and the settings store), `doctor/` (the `run_doctor` tool
|
|
740
|
-
and its probe runtime), and `notify/`.
|
|
952
|
+
and its probe runtime), and `notify/`. The chrome and the screen are drawn from
|
|
953
|
+
the package's [`lib/tui/`](../../lib/tui/) design system (tokens, rules, rows,
|
|
954
|
+
columns, gauge), so the look follows the active theme.
|
|
741
955
|
|
|
742
956
|
| File | Responsibility |
|
|
743
957
|
|---|---|
|
|
744
|
-
| `index.ts` | Composition root: the disable guard
|
|
745
|
-
| `
|
|
746
|
-
| `
|
|
958
|
+
| `index.ts` | Composition root: the disable guard, the eleven `register*` calls, the one shared output-pad store, and the rail source. |
|
|
959
|
+
| `pad.ts` | `PadSource` and `createPadStore`: one record of Pi's output pad, so the tool frame, the notice, and the turn separator inset by the same margin. |
|
|
960
|
+
| `chrome.ts` | The transcript rail (`RAIL_ROLES`, `railGlyph`), the `chrome` section's normalizer and loader, and the `RailSource` that `registerChrome` keeps current on `session_start`/`session_tree`. |
|
|
961
|
+
| `header/config.ts` | Header tuning (`HEADER_CONFIG`): mark and identity roles, tagline, and the grouped help entries. |
|
|
962
|
+
| `header/component.ts` | `ByteflyHeader`: the mark, identity rows, signature rule, and grouped help, plus its factory. |
|
|
747
963
|
| `header/register.ts` | Installs/restores the header and owns its session lifecycle. |
|
|
748
964
|
| `footer/register.ts` | Installs/restores the footer and owns its session lifecycle. |
|
|
749
965
|
| `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, status keys, labels. |
|
|
@@ -755,22 +971,35 @@ and its probe runtime), and `notify/`.
|
|
|
755
971
|
| `footer/price/rates.ts` | Model-key matching: exact and wildcard, most specific first. |
|
|
756
972
|
| `footer/price/schedule.ts` | Peak-window parsing and evaluation in a configured zone. |
|
|
757
973
|
| `footer/price/price.ts` | Records → totals: rates, peak multiplier, recorded-cost fallback. |
|
|
758
|
-
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd,
|
|
974
|
+
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd, the context role, truncation). |
|
|
759
975
|
| `footer/render/status.ts` | Status-chip transforms: `compactStatus` and `dropStatusDetail`. |
|
|
760
|
-
| `footer/render/segments.ts` | The segment builders: forms, weights, separators,
|
|
976
|
+
| `footer/render/segments.ts` | The segment builders: forms, weights, separators, roles. |
|
|
761
977
|
| `footer/render/lines.ts` | Snapshot → two `LineSpec`s; status routing. |
|
|
762
978
|
| `footer/render/layout.ts` | Width reduction and right-zone folding. |
|
|
763
979
|
| `footer/render/footer.ts` | `StatusBar` component and footer factory. |
|
|
764
|
-
| `
|
|
980
|
+
| `message/config.ts` | Nameplate tuning (`MESSAGE_CONFIG`): the label and the rule. |
|
|
981
|
+
| `message/format.ts` | Pure `nameplate` and `styleUserMessage`: the two-row nameplate (label over a full-width rule) and its placement above the message. |
|
|
982
|
+
| `message/register.ts` | Registers the Markdown transformer. |
|
|
983
|
+
| `notice/config.ts` | Notice tuning (`NOTICE_CONFIG`): source/title/detail roles, the severity glyphs and roles, the shared rail roles, and the item cap. |
|
|
984
|
+
| `notice/component.ts` | Pure `noticeLines` and `NoticeComponent`: the headline at the margin, the rail-led severity rows, sanitized and width-clipped. |
|
|
985
|
+
| `notice/register.ts` | Registers the message renderer for the shared notice type and hands it the rail source. |
|
|
986
|
+
| `block/config.ts` | `BlockStatus` and `BLOCK_CONFIG.roles`: the design role a result's rail takes for each state. |
|
|
987
|
+
| `block/component.ts` | Pure `toolBlockLines`, `headlineWithToolName`, `recolorShellCall`, `recolorCallHeadline`, and `ToolBlock`: the headline, the body's two-column indent (optionally rail-led), the reduced-width inner render, the leading-blank trim, the shell-prompt rewrite (the name keeps the accent, the command reopens in `label`), the subject demotion (a path, URL, query, or pattern reads in `label` so the name is the line's only accent, including the tail a bare `edit <path>` headline wraps onto the body), and the image-line passthrough. |
|
|
988
|
+
| `block/fallback.ts` | Generic `callFallback` / `resultFallback` for a tool with no renderer: the subject in the body colour, its options faint, and a capped result preview. |
|
|
989
|
+
| `block/register.ts` | The `registerToolRenderer` resolver that frames every tool; it recolours a shell call's string before the frame wraps it, rails the result body by status, and rails the call body for `edit`/`write` (the two whose call body carries the result). |
|
|
990
|
+
| `separator/config.ts` | Turn-rule tuning: `customType`, glyph, label prefix, padding, and roles. |
|
|
765
991
|
| `separator/register.ts` | Registers the entry renderer and appends a separator on `agent_settled`. |
|
|
766
992
|
| `separator/component.ts` | `SeparatorComponent`: the stateless entry renderer. |
|
|
767
|
-
| `separator/format.ts` | Pure `
|
|
768
|
-
| `separator/types.ts` | `TurnSeparatorData
|
|
993
|
+
| `separator/format.ts` | Pure `separatorLine`: the centered turn rule, drawn by the kit's `centeredRule`. |
|
|
994
|
+
| `separator/types.ts` | `TurnSeparatorData`. |
|
|
995
|
+
| `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the word, the ellipsis, and the tick interval. |
|
|
996
|
+
| `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape. |
|
|
997
|
+
| `working/register.ts` | Starts the tick on `turn_start` and cancels it on `agent_end`/`session_shutdown`. |
|
|
769
998
|
| `panel/types.ts` | `PanelRow` and `PanelModel`, the merged row model. |
|
|
770
999
|
| `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering. |
|
|
771
1000
|
| `panel/format.ts` | Non-TUI text: the headline and the grouped listing with a per-row health suffix. |
|
|
772
|
-
| `panel/tui.ts` | `PanelComponent`, the unified dock screen. |
|
|
773
|
-
| `panel/commands.ts` | `/bytefly
|
|
1001
|
+
| `panel/tui.ts` | `PanelComponent`, the unified dock screen, drawn from the `lib/tui/` kit. |
|
|
1002
|
+
| `panel/commands.ts` | `/bytefly`: one command for the screen, the `doctor` report, and their text modes. |
|
|
774
1003
|
| `picker/types.ts` | Picker host seams (`SettingsStore`, `ExtensionResolver`, `Discovery`) and row types. |
|
|
775
1004
|
| `picker/resources.ts` | Pure grouping, labels, display names, and pattern helpers. |
|
|
776
1005
|
| `picker/toggle.ts` | Pure next-settings transforms for global and project toggles. |
|
|
@@ -781,7 +1010,7 @@ and its probe runtime), and `notify/`.
|
|
|
781
1010
|
| `doctor/tools.ts` | The `run_doctor` tool and its renderers. |
|
|
782
1011
|
| `doctor/schema.ts` | Tool parameters and the structured output schema. |
|
|
783
1012
|
| `doctor/config.ts` | `DEFAULT_CONFIG`, `normalizeConfig`, `loadConfig` for the `doctor` section of `bytefly.json`. |
|
|
784
|
-
| `doctor/format.ts` | Pure report text, summary, glyphs, detail lines, and the proactive warning sentence. |
|
|
1013
|
+
| `doctor/format.ts` | Pure report text, summary, severity roles and glyphs, detail lines, and the proactive warning sentence. |
|
|
785
1014
|
| `notify/types.ts` | `NotifyConfig`, `NotifyMethod`, and the method list. |
|
|
786
1015
|
| `notify/config.ts` | The `notify` section of `bytefly.json`: defaults, validation, loader. |
|
|
787
1016
|
| `notify/dispatch.ts` | Method selection and delivery: OSC 777/99, Windows toast, `osascript`, `notify-send`, over injected seams. |
|
|
@@ -825,3 +1054,12 @@ through the factory (`doctor/register`). The notify capability is covered by its
|
|
|
825
1054
|
(`notify/config`), the pure text builders (`notify/format`), method selection and
|
|
826
1055
|
delivery over recording seams (`notify/dispatch`), and its three triggers,
|
|
827
1056
|
reload, and shutdown through `registerNotify` (`notify/register`).
|
|
1057
|
+
The user-message nameplate is covered by its pure transform
|
|
1058
|
+
(`message/format`, including a render through pi-tui's real `Markdown`) and its
|
|
1059
|
+
registration (`message/register`), plus the factory check in `extension`.
|
|
1060
|
+
The notice surface is covered by its pure rows (`notice/component`), its
|
|
1061
|
+
renderer registration (`notice/register`), and the shared contract
|
|
1062
|
+
(`lib/notice`), plus the factory check in `extension`.
|
|
1063
|
+
The tool-block frame is covered by its pure `toolBlockLines` (`block/component`)
|
|
1064
|
+
and its generic fallback (`block/fallback`), plus the resolver's shell override,
|
|
1065
|
+
self-shell carve-out, and fallback framing (`block/register`).
|