@gavin-hu/my-pi-agent 0.13.1 → 0.15.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 -41
- package/README.zh-CN.md +53 -36
- package/extensions/bytefly/README.md +321 -186
- package/extensions/bytefly/block/component.ts +7 -15
- package/extensions/bytefly/block/register.ts +6 -1
- package/extensions/bytefly/doctor/config.ts +4 -1
- package/extensions/bytefly/doctor/register.ts +24 -5
- package/extensions/bytefly/doctor/tools.ts +4 -0
- package/extensions/bytefly/footer/collect/snapshot.ts +6 -1
- package/extensions/bytefly/footer/config.ts +10 -6
- package/extensions/bytefly/footer/price/config.ts +3 -2
- package/extensions/bytefly/footer/price/price.ts +5 -3
- package/extensions/bytefly/footer/price/rates.ts +63 -26
- package/extensions/bytefly/footer/render/status.ts +3 -3
- package/extensions/bytefly/header/component.ts +33 -10
- package/extensions/bytefly/header/config.ts +22 -0
- package/extensions/bytefly/header/register.ts +2 -1
- package/extensions/bytefly/index.ts +6 -6
- package/extensions/bytefly/notice/component.ts +8 -3
- package/extensions/bytefly/notify/config.ts +7 -12
- package/extensions/bytefly/notify/dispatch.ts +13 -5
- package/extensions/bytefly/panel/commands.ts +22 -2
- package/extensions/bytefly/panel/format.ts +17 -21
- package/extensions/bytefly/panel/settings-runtime.ts +86 -22
- package/extensions/bytefly/panel/settings.ts +279 -46
- package/extensions/bytefly/panel/themes.ts +32 -0
- package/extensions/bytefly/panel/tui/editing.ts +77 -0
- package/extensions/bytefly/panel/tui/entries.ts +24 -0
- package/extensions/bytefly/panel/tui/extensions-view.ts +13 -8
- package/extensions/bytefly/panel/tui/frame.ts +121 -4
- package/extensions/bytefly/panel/tui/settings-view.ts +98 -13
- package/extensions/bytefly/panel/tui.ts +176 -166
- package/extensions/bytefly/picker/discovery.ts +1 -0
- package/extensions/bytefly/picker/types.ts +2 -0
- package/extensions/bytefly/separator/component.ts +17 -6
- package/extensions/bytefly/separator/config.ts +15 -0
- package/extensions/bytefly/separator/format.ts +60 -6
- package/extensions/bytefly/separator/register.ts +68 -9
- package/extensions/bytefly/separator/types.ts +8 -0
- package/extensions/bytefly/update/cache.ts +58 -19
- package/extensions/bytefly/update/check.ts +35 -0
- package/extensions/bytefly/update/format.ts +76 -35
- package/extensions/bytefly/update/register.ts +144 -55
- package/extensions/bytefly/update/state.ts +4 -2
- package/extensions/bytefly/update/suppress.ts +66 -0
- package/extensions/bytefly/update/types.ts +15 -0
- package/extensions/bytefly/working/config.ts +4 -5
- package/extensions/bytefly/working/format.ts +24 -7
- package/extensions/bytefly/working/register.ts +34 -3
- package/extensions/check/README.md +253 -0
- package/extensions/check/commands.ts +128 -0
- package/extensions/check/config.ts +39 -0
- package/extensions/check/detect.ts +269 -0
- package/extensions/check/failures.ts +230 -0
- package/extensions/check/format.ts +135 -0
- package/extensions/check/index.ts +26 -0
- package/extensions/check/render.ts +185 -0
- package/extensions/check/runner.ts +176 -0
- package/extensions/check/runtime.ts +244 -0
- package/extensions/check/source.ts +80 -0
- package/extensions/check/tools.ts +173 -0
- package/extensions/check/tui.ts +195 -0
- package/extensions/check/types.ts +99 -0
- package/extensions/document/README.md +1 -1
- package/extensions/document/extract/pdf.ts +8 -16
- package/extensions/document/formats.ts +2 -2
- package/extensions/file-browse/README.md +66 -32
- package/extensions/file-browse/client.ts +95 -32
- package/extensions/file-browse/config.ts +9 -9
- package/extensions/file-browse/git.ts +37 -47
- package/extensions/file-browse/html.ts +39 -58
- package/extensions/file-browse/markdown.ts +110 -92
- package/extensions/file-browse/raw-html.ts +478 -0
- package/extensions/file-browse/router.ts +32 -70
- package/extensions/file-browse/server.ts +18 -56
- package/extensions/file-browse/urls.ts +80 -0
- package/extensions/goal/README.md +103 -47
- package/extensions/goal/clarify-parse.ts +4 -9
- package/extensions/goal/clarify.ts +27 -4
- package/extensions/goal/commands.ts +24 -11
- package/extensions/goal/format.ts +41 -10
- package/extensions/goal/index.ts +39 -16
- package/extensions/goal/plan-route.ts +51 -0
- package/extensions/goal/schema.ts +6 -23
- package/extensions/goal/state.ts +39 -57
- package/extensions/goal/tools.ts +26 -20
- package/extensions/goal/types.ts +11 -1
- package/extensions/job/README.md +20 -6
- package/extensions/job/format.ts +18 -68
- package/extensions/job/index.ts +26 -41
- package/extensions/job/log-writer.ts +208 -0
- package/extensions/job/logs.ts +3 -2
- package/extensions/job/process.ts +6 -99
- package/extensions/job/runtime.ts +42 -181
- package/extensions/job/schema.ts +1 -4
- package/extensions/job/tools.ts +1 -15
- package/extensions/job/tui.ts +117 -307
- package/extensions/job/ui.ts +7 -33
- package/extensions/memory/README.md +3 -1
- package/extensions/memory/errors.ts +5 -6
- package/extensions/memory/tui.ts +14 -24
- package/extensions/plan/README.md +106 -18
- package/extensions/plan/commands.ts +9 -5
- package/extensions/plan/format.ts +87 -0
- package/extensions/plan/index.ts +31 -15
- package/extensions/plan/plans.ts +2 -3
- package/extensions/plan/policy.ts +0 -6
- package/extensions/plan/runtime.ts +4 -2
- package/extensions/plan/steps.ts +37 -8
- package/extensions/plan/todos.ts +44 -3
- package/extensions/plan/tools/enter.ts +94 -0
- package/extensions/plan/tools/exit.ts +296 -0
- package/extensions/plan/tools/nested.ts +21 -0
- package/extensions/plan/tools/steps.ts +136 -0
- package/extensions/plan/tools/todo-seed.ts +76 -0
- package/extensions/plan/tools/write.ts +127 -0
- package/extensions/plan/tools.ts +18 -703
- package/extensions/plan/web-client.ts +6 -22
- package/extensions/plan/web-page.ts +19 -30
- package/extensions/plan/web-router.ts +34 -71
- package/extensions/plan/web.ts +13 -40
- package/extensions/question/answers.ts +3 -8
- package/extensions/question/tui.ts +6 -6
- package/extensions/rewind/README.md +95 -22
- package/extensions/rewind/checklist.ts +185 -0
- package/extensions/rewind/commands.ts +8 -0
- package/extensions/rewind/config.ts +3 -11
- package/extensions/rewind/format.ts +220 -2
- package/extensions/rewind/git.ts +74 -7
- package/extensions/rewind/hunk-picker.ts +114 -0
- package/extensions/rewind/patch.ts +88 -0
- package/extensions/rewind/path-picker.ts +67 -100
- package/extensions/rewind/paths.ts +93 -19
- package/extensions/rewind/restore.ts +53 -10
- package/extensions/rewind/review-tui.ts +320 -0
- package/extensions/rewind/review.ts +397 -0
- package/extensions/rewind/rewind-tui.ts +4 -3
- package/extensions/rewind/runtime.ts +94 -17
- package/extensions/subagent/README.md +118 -8
- package/extensions/subagent/background-tui.ts +208 -0
- package/extensions/subagent/background.ts +470 -0
- package/extensions/subagent/commands.ts +80 -0
- package/extensions/subagent/config.ts +62 -0
- package/extensions/subagent/format.ts +24 -1
- package/extensions/subagent/index.ts +116 -1
- package/extensions/subagent/orchestrate.ts +16 -3
- package/extensions/subagent/render.ts +25 -0
- package/extensions/subagent/run.ts +113 -49
- package/extensions/subagent/schema.ts +12 -0
- package/extensions/subagent/transcripts.ts +202 -0
- package/extensions/subagent/types.ts +23 -0
- package/extensions/subagent/ui.ts +50 -0
- package/extensions/todo/README.md +18 -13
- package/extensions/todo/format.ts +3 -2
- package/extensions/todo/runtime.ts +3 -2
- package/extensions/todo/schema.ts +8 -84
- package/extensions/todo/state.ts +5 -46
- package/extensions/todo/tools.ts +2 -1
- package/extensions/todo/types.ts +6 -15
- package/extensions/watch/README.md +16 -6
- package/extensions/watch/child.ts +150 -0
- package/extensions/watch/format.ts +8 -48
- package/extensions/watch/index.ts +42 -58
- package/extensions/watch/runtime.ts +49 -128
- package/extensions/watch/schema.ts +1 -4
- package/extensions/watch/tools.ts +1 -11
- package/extensions/watch/tui.ts +103 -273
- package/extensions/watch/ui.ts +5 -32
- package/extensions/web-access/README.md +1 -1
- package/extensions/web-access/fetch/page.ts +1 -1
- package/extensions/web-access/fetch/tool.ts +6 -2
- package/extensions/web-access/search/search.ts +2 -5
- package/extensions/wechat/README.md +3 -1
- package/extensions/wechat/client.ts +23 -0
- package/extensions/wechat/commands.ts +57 -42
- package/extensions/wechat/deliver.ts +5 -9
- package/extensions/wechat/errors.ts +3 -6
- package/extensions/wechat/inbound.ts +2 -5
- package/extensions/wechat/index.ts +2 -8
- package/extensions/wechat/outbound.ts +2 -4
- package/extensions/wechat/peer-worker.ts +3 -8
- package/extensions/wechat/poll.ts +10 -9
- package/extensions/wechat/presence.ts +35 -62
- package/extensions/wechat/reply-pipeline.ts +3 -1
- package/extensions/wechat/status-screen.ts +1 -1
- package/extensions/wechat/timer.ts +57 -0
- package/extensions/worktree/config.ts +8 -20
- package/extensions/worktree/enter.ts +7 -12
- package/extensions/worktree/git.ts +38 -69
- package/extensions/worktree/index.ts +5 -4
- package/extensions/worktree/registry.ts +7 -7
- package/extensions/worktree/root-tools.ts +2 -2
- package/extensions/worktree/status.ts +3 -2
- package/lib/README.md +22 -8
- package/lib/config.ts +83 -12
- package/lib/errors.ts +12 -0
- package/lib/format.ts +56 -0
- package/lib/git/read.ts +8 -0
- package/lib/goal-state.ts +23 -8
- package/lib/http/headers.ts +54 -0
- package/lib/http/index.ts +13 -0
- package/lib/http/response.ts +46 -0
- package/lib/http/router.ts +52 -0
- package/lib/http/server.ts +91 -0
- package/lib/lines.ts +77 -0
- package/lib/pdf.ts +82 -0
- package/lib/plan-entry.ts +71 -0
- package/lib/plan-state.ts +34 -0
- package/lib/report.ts +99 -0
- package/lib/requirements.ts +25 -19
- package/lib/spawn.ts +170 -0
- package/lib/todo-state.ts +110 -23
- package/lib/tool-names.ts +7 -0
- package/lib/tool-result.ts +33 -0
- package/lib/tui/README.md +68 -3
- package/lib/tui/chrome.ts +28 -4
- package/lib/tui/columns.ts +6 -1
- package/lib/tui/confirm.ts +65 -0
- package/lib/tui/dock-screen.ts +410 -0
- package/lib/tui/glyphs.ts +2 -1
- package/lib/tui/indent.ts +1 -1
- package/lib/tui/index.ts +2 -0
- package/lib/tui/rows.ts +21 -0
- package/lib/tui/status-controller.ts +35 -1
- package/lib/tui/tool.ts +59 -1
- package/lib/web/components.ts +20 -1
- package/lib/web/markup.ts +32 -0
- package/lib/web/runtime.ts +50 -0
- package/package.json +23 -5
- package/skills/init/SKILL.md +165 -0
- package/skills/init/references/agents-md-quality.md +103 -0
- package/skills/init/references/interview-questions.md +81 -0
- package/skills/refactor/SKILL.md +141 -0
- package/themes/bytefly-dark.json +2 -3
- package/themes/bytefly-light.json +2 -3
- package/extensions/watch/process.ts +0 -63
- package/extensions/web-access/fetch/pdf.ts +0 -45
|
@@ -3,13 +3,14 @@
|
|
|
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 two-row `You` nameplate that opens each user message, a
|
|
7
|
-
|
|
6
|
+
footer, a two-row `You` nameplate that opens each user message, a receipt rule that
|
|
7
|
+
records each completed turn in the transcript, one keyboard-driven screen with two
|
|
8
8
|
sections — Extensions, every resolved Pi extension with its enable checkbox and
|
|
9
9
|
its health, and Settings, the common app and `bytefly.json` preferences — and
|
|
10
10
|
an opt-in notify capability that raises an OS notification when a run finishes,
|
|
11
|
-
a job finishes, or the agent asks for input, and a
|
|
12
|
-
|
|
11
|
+
a job finishes, or the agent asks for input, and a package-update check that
|
|
12
|
+
replaces Pi's startup block with one notice and marks bytefly's own new version
|
|
13
|
+
on the header.
|
|
13
14
|
DeepSeek is priced from the provider's published yuan rates and peak tariff by
|
|
14
15
|
default; set `price.currency.code` to `USD` to price it from the provider's
|
|
15
16
|
published dollar table instead, under the same peak windows, with Pi's recorded
|
|
@@ -33,8 +34,8 @@ How the `run_doctor` call and its result look in the transcript — the call lin
|
|
|
33
34
|
|
|
34
35
|
The extension owns ten surfaces: the startup header, the footer, the
|
|
35
36
|
user-message marker, the rule between completed turns, the notice block for
|
|
36
|
-
shared transcript notices, the tool-block frame, the live working
|
|
37
|
-
two-section control center, notifications, and the
|
|
37
|
+
shared transcript notices, the tool-block frame, the live working line, the
|
|
38
|
+
two-section control center, notifications, and the package-update check.
|
|
38
39
|
|
|
39
40
|
**Header.** A nameplate: a two-tone half-block mark from the active theme's
|
|
40
41
|
`accent` / `warn` roles, the agent identity (`Pi`, bold, and its version), the
|
|
@@ -59,10 +60,15 @@ that cannot render half blocks the mark falls back to a two-tone `Pi` wordmark.
|
|
|
59
60
|
|
|
60
61
|
As the terminal narrows, the identity sheds the update marker, then the chrome
|
|
61
62
|
version, then the chrome line, then the agent name, and the help rows drop whole
|
|
62
|
-
keys, so nothing wraps or clips mid-word.
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
keys, so nothing wraps or clips mid-word. Height sheds the same way: at 28 rows
|
|
64
|
+
all three help groups print, below 28 the middle group (the expand and model
|
|
65
|
+
chords) goes first, below 22 only the `/` commands row survives, and below 16 the
|
|
66
|
+
help block and the leading blank row go, leaving the nameplate and its rule. An
|
|
67
|
+
unknown height keeps the full header. The nameplate sits on the transcript
|
|
68
|
+
margin, which follows Pi's `outputPad` (the value the tool frame and the notice
|
|
69
|
+
use too), and the help hangs one body indent inside it. The mark, tokens,
|
|
70
|
+
identity, and grouped help are tuned in
|
|
71
|
+
[`header/config.ts`](./header/config.ts).
|
|
66
72
|
|
|
67
73
|
**Footer.** Two lines, each with a left and right zone:
|
|
68
74
|
|
|
@@ -70,7 +76,7 @@ in [`header/config.ts`](./header/config.ts).
|
|
|
70
76
|
(`⎇ branch · ⑂ worktree`) and the `◉` browse chip on the right.
|
|
71
77
|
- **Line 2 — resources:** the context gauge and usage meters on the left, the
|
|
72
78
|
child-run roll-up (`↳ 3 · ¥0.12`, present only once a subagent has finished),
|
|
73
|
-
the mode/alert slot (
|
|
79
|
+
the mode/alert slot (`≡ plan`) trailing after a `│` when present, and the model
|
|
74
80
|
and thinking level on the right. The gauge is anchored at column 0, so `%` is
|
|
75
81
|
always in the same place.
|
|
76
82
|
The roll-up is its own number, never folded into the session's cost: a subagent
|
|
@@ -81,7 +87,7 @@ in [`header/config.ts`](./header/config.ts).
|
|
|
81
87
|
|
|
82
88
|
```
|
|
83
89
|
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
84
|
-
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↳ 2 · ¥0.06 · ↑42k ↓8.0k · R96k CH 87%
|
|
90
|
+
▰▰▰▰▰▰▱▱▱▱ 62%/200k · ¥0.31 · ↳ 2 · ¥0.06 · ↑42k ↓8.0k · R96k CH 87% │ ≡ plan opus-4.5 · high
|
|
85
91
|
```
|
|
86
92
|
|
|
87
93
|
(The examples show the default `¥` symbol. A model that neither `rates` nor the
|
|
@@ -89,7 +95,7 @@ built-in table covers contributes nothing in `CNY` mode, so the bar shows no
|
|
|
89
95
|
figure rather than a guessed one; `USD` mode adds Pi's recorded dollars for that
|
|
90
96
|
record instead — see the currency note under [Configuration](#configuration).)
|
|
91
97
|
|
|
92
|
-
With no plan mode there is no mode slot, so the
|
|
98
|
+
With no plan mode there is no mode slot, so the `│` is omitted:
|
|
93
99
|
|
|
94
100
|
```
|
|
95
101
|
~/repo/my-pi-agent ⎇ main · ⑂ smoke
|
|
@@ -102,19 +108,19 @@ fits, rather than collapsing to a bare glyph:
|
|
|
102
108
|
|
|
103
109
|
```
|
|
104
110
|
~/repo/project ⎇ main · ⑂ smoke
|
|
105
|
-
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31
|
|
111
|
+
▰▰▰▰▰▰▱▱▱▱ 62% · ¥0.31 │ ≡ plan opus-4.5 · high
|
|
106
112
|
```
|
|
107
113
|
|
|
108
114
|
```
|
|
109
115
|
project ⎇ main
|
|
110
|
-
62%
|
|
116
|
+
62% ≡ opus-4.5
|
|
111
117
|
```
|
|
112
118
|
|
|
113
119
|
With a named session, the name follows the path and truncates before it drops:
|
|
114
120
|
|
|
115
121
|
```
|
|
116
122
|
~/repo/project · feature-refac… ⎇ main
|
|
117
|
-
▰▰▰▰▰▰▱▱▱▱ 62%
|
|
123
|
+
▰▰▰▰▰▰▱▱▱▱ 62% │ ≡ plan opus-4.5
|
|
118
124
|
```
|
|
119
125
|
|
|
120
126
|
Zero-value meters are omitted, so a fresh session shows only `?/window` instead
|
|
@@ -168,26 +174,36 @@ as it would without it, and a soft wrap of one long line stays at the margin
|
|
|
168
174
|
because the renderer wraps it, not bytefly. The label and the rule are tuned
|
|
169
175
|
in [`message/config.ts`](./message/config.ts).
|
|
170
176
|
|
|
171
|
-
**Working
|
|
177
|
+
**Working line.** Pi's working row shows a static `Working`, so a long run
|
|
172
178
|
reads the same as a short one. While the row is up, bytefly advances its
|
|
173
|
-
message once a second and hands it back to Pi when the row comes down
|
|
179
|
+
message once a second and hands it back to Pi when the row comes down. Before
|
|
180
|
+
the first tool starts it is a count:
|
|
174
181
|
|
|
175
182
|
```
|
|
176
183
|
Working… 12s
|
|
177
184
|
```
|
|
178
185
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
Once a top-level tool starts, the row becomes a live run line: the tool, how
|
|
187
|
+
many top-level tools this run has started, and the elapsed time.
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
edit · 3 tools · 12s
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
A nested tool call (one carrying `parentToolCallId`, such as a codemode script's
|
|
194
|
+
inner call) neither counts nor takes over the line, so the number matches the
|
|
195
|
+
tool blocks in the transcript. The line keeps the last tool name while the
|
|
196
|
+
model streams after it, and a tool event repaints the row immediately instead
|
|
197
|
+
of waiting for the next tick. The line covers the whole run, tool calls
|
|
198
|
+
included. It is tied to the row's visibility: it starts on `turn_start`, stops
|
|
199
|
+
on `agent_end`, and is reset on `session_shutdown`; turns inside one run do not
|
|
200
|
+
restart it, and a retry starts a new run. The words and the interval are tuned
|
|
201
|
+
in [`working/config.ts`](./working/config.ts).
|
|
186
202
|
|
|
187
203
|
**Turn separator.** After each completed turn the extension appends an inert
|
|
188
|
-
entry and draws a centered `╌╌╌ turn N
|
|
189
|
-
[Turn separator](#turn-separator). No config file is
|
|
190
|
-
command.
|
|
204
|
+
entry and draws a centered receipt rule — `╌╌╌ turn N · duration · N tools ╌╌╌`
|
|
205
|
+
— across the transcript; see [Turn separator](#turn-separator). No config file is
|
|
206
|
+
needed and there is no command.
|
|
191
207
|
|
|
192
208
|
**Notices.** Any extension in the package can post a transcript notice under the
|
|
193
209
|
shared `my-pi-agent/notice` type; bytefly draws it at the transcript's margin —
|
|
@@ -219,6 +235,15 @@ are tuned in [`notice/config.ts`](./notice/config.ts). Every field is sanitized
|
|
|
219
235
|
and clipped at the boundary, and a message without `details` keeps Pi's default
|
|
220
236
|
custom-message box.
|
|
221
237
|
|
|
238
|
+
**Compaction.** `/compact` is Pi's own surface: its summary block is a built-in
|
|
239
|
+
message component, so bytefly cannot replace, hide, or shorten it. The shipped
|
|
240
|
+
themes only remove its fill — `customMessageBg` is the terminal default — and
|
|
241
|
+
paint the `[compaction]` label in the accent, so the block sits on the canvas
|
|
242
|
+
like the rest of the transcript. Pi's branch summaries and skill invocations
|
|
243
|
+
share the same tokens.
|
|
244
|
+
|
|
245
|
+
<img src="../../assets/compaction.png" alt="The /compact summary block: a [compaction] label, the compacted token count, and the summary Markdown on the terminal canvas, with no background band" width="100%">
|
|
246
|
+
|
|
222
247
|
**Tool blocks.** Every tool block leads with the tool's own call line as the
|
|
223
248
|
headline — the tool name in the theme's tool-title colour — and its result body
|
|
224
249
|
sits two columns in directly beneath it, led by the transcript rail, instead of
|
|
@@ -294,15 +319,17 @@ method follows the terminal (OSC 777, OSC 99, a Windows toast) or falls back to
|
|
|
294
319
|
the platform notifier (`osascript`, `notify-send`); see
|
|
295
320
|
[Notifications](#notifications).
|
|
296
321
|
|
|
297
|
-
**Update check.** In the background at an interactive session's start,
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
322
|
+
**Update check.** In the background at an interactive session's start, Pi's
|
|
323
|
+
package manager reports which configured packages are behind. bytefly suppresses
|
|
324
|
+
Pi's own startup block, caches the snapshot in `<agentDir>/bytefly/update.json`
|
|
325
|
+
with the time it was read, and posts one transcript notice listing every package
|
|
326
|
+
plus `pi update --extensions`. This package's new version alone puts `↑0.12.0`
|
|
327
|
+
after the header's chrome version and adds its release URL to the notice. A
|
|
328
|
+
session inside the 24-hour window reuses the cache without a package-manager
|
|
329
|
+
call, and `/bytefly update` re-runs the check on demand. `PI_OFFLINE` uses the
|
|
330
|
+
cached marker with no notice, only `tui` starts the background check, and a
|
|
331
|
+
failed read is silent and not cached, so the next session tries again; see
|
|
332
|
+
[Update check](#update-check).
|
|
306
333
|
|
|
307
334
|
## Commands
|
|
308
335
|
|
|
@@ -311,7 +338,7 @@ request is silent; see [Update check](#update-check).
|
|
|
311
338
|
| `/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. |
|
|
312
339
|
| `/bytefly settings` | Open the control center on Settings. Outside `tui` it prints the grouped settings listing with each row's value. |
|
|
313
340
|
| `/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. |
|
|
314
|
-
| `/bytefly update` | Re-run the
|
|
341
|
+
| `/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. |
|
|
315
342
|
|
|
316
343
|
Tab completes the subcommands, extension names after `doctor`, and `refresh`;
|
|
317
344
|
`/bytefly settings` and `/bytefly update` take no name.
|
|
@@ -348,10 +375,10 @@ identity tokens, tagline, grouped help), the footer in
|
|
|
348
375
|
[`footer/config.ts`](./footer/config.ts) (thresholds, gauge glyphs and widths,
|
|
349
376
|
separators, icons, status keys), and the turn separator in
|
|
350
377
|
[`separator/config.ts`](./separator/config.ts) (glyph, label prefix, padding,
|
|
351
|
-
colors).
|
|
378
|
+
minimum duration, outcome wording, colors).
|
|
352
379
|
|
|
353
|
-
Every key of every section is listed with its type, default, and bounds in
|
|
354
|
-
[configuration
|
|
380
|
+
Every key of every section is listed with its type, default, and bounds in
|
|
381
|
+
[`docs/configuration.md`](../../docs/configuration.md); this section
|
|
355
382
|
covers what that table cannot — when each section is read, and what the cost
|
|
356
383
|
does when no rate matches.
|
|
357
384
|
|
|
@@ -448,7 +475,10 @@ it with its own rates for the models they match:
|
|
|
448
475
|
- **Which rate.** The most specific key wins, with the model segment outranking
|
|
449
476
|
the provider one: `provider/model`, then `*/model`, then `provider/*`, then
|
|
450
477
|
`*`. A segment ending in a star is a prefix match (`*/gpt-*`); equally
|
|
451
|
-
specific keys are resolved in file order.
|
|
478
|
+
specific keys are resolved in file order. A key splits at its first slash, so
|
|
479
|
+
the model segment may contain one: an OpenRouter id is
|
|
480
|
+
`anthropic/claude-fable-5` and its key is
|
|
481
|
+
`openrouter/anthropic/claude-fable-5`.
|
|
452
482
|
- **Which formula.** `tokens × rate ÷ 1,000,000`, summed over the four token
|
|
453
483
|
classes. Cache tokens are never billed again as fresh input.
|
|
454
484
|
- **Which tariff.** Each record is dated by its session entry, so a window is
|
|
@@ -495,9 +525,9 @@ The worktree status is read from the `worktree` status key, so the
|
|
|
495
525
|
from the `browse` status key published by [file-browse](../file-browse/) while
|
|
496
526
|
its server runs, and shows the two-tone `◉ <port>` (green glyph, accent port).
|
|
497
527
|
The trailing slot shows plan-style alerts when present and is omitted otherwise;
|
|
498
|
-
a plan chip's trailing plan file name is dropped, so the slot reads
|
|
528
|
+
a plan chip's trailing plan file name is dropped, so the slot reads `≡ plan`
|
|
499
529
|
even though the built-in footer keeps the name. An alert (a failed job) sorts to
|
|
500
|
-
the front of the slot. The slot trails the meters after a
|
|
530
|
+
the front of the slot. The slot trails the meters after a `│`, so the context
|
|
501
531
|
gauge always starts the line. It keeps each extension's own colour when it
|
|
502
532
|
compacts, and it is droppable: a tight bar drops the slot rather than truncating
|
|
503
533
|
the model, which sits at the end of the line.
|
|
@@ -507,32 +537,46 @@ the model, which sits at the end of the line.
|
|
|
507
537
|
`agent_settled` fires once after an agent run fully settles — exactly one user
|
|
508
538
|
turn — which is why it is used instead of `turn_end` (that fires once per
|
|
509
539
|
assistant message, so tool-calling rounds would each get a line). On each
|
|
510
|
-
settled run the extension appends an inert custom entry and a renderer draws
|
|
511
|
-
|
|
540
|
+
settled run the extension appends an inert custom entry and a renderer draws it
|
|
541
|
+
as a receipt: the turn number, then the run's duration, top-level tool count,
|
|
542
|
+
and outcome as the width allows.
|
|
512
543
|
|
|
513
544
|
```
|
|
514
|
-
|
|
545
|
+
╌╌╌╌╌╌╌╌╌╌╌╌ turn 3 · 1m12s · 7 tools ╌╌╌╌╌╌╌╌╌╌╌╌
|
|
515
546
|
```
|
|
516
547
|
|
|
517
548
|
- The turn number is `count(separators on the current branch) + 1`, so a
|
|
518
549
|
resumed or forked session continues the parent's numbering and abandoned
|
|
519
550
|
branches do not leak counts.
|
|
551
|
+
- The receipt opens on the run's first `agent_start` and closes on
|
|
552
|
+
`agent_settled`, so a retry stays inside one duration. It counts only
|
|
553
|
+
top-level tool calls; a nested call (one carrying `parentToolCallId`) is an
|
|
554
|
+
implementation detail of its parent and does not inflate the number.
|
|
555
|
+
- The outcome is part of the receipt: a failed tool adds `✕N`, and an aborted
|
|
556
|
+
run adds `aborted` instead of the failure count. A sub-second run prints no
|
|
557
|
+
duration, so quick turns stay quiet. Entries written before the receipt
|
|
558
|
+
existed have only a turn number and still render as `turn N`.
|
|
559
|
+
- The label sheds fields rather than overflowing: the tool count first, then
|
|
560
|
+
the duration, then the outcome. When even the turn number does not fit, the
|
|
561
|
+
line becomes a plain dashed rule instead of clipping.
|
|
562
|
+
- A clean turn paints the label `meta`, a turn with a failed tool paints it
|
|
563
|
+
`bad`, and an aborted turn paints it `warn`.
|
|
520
564
|
- The entry is excluded from LLM context, so it costs no tokens, and it
|
|
521
565
|
survives resume and fork. It is drawn under the `bytefly-separator` custom
|
|
522
566
|
entry type.
|
|
523
|
-
- The line is centered and width-adaptive: the label is filled out with the
|
|
524
|
-
glyph, and when it cannot fit the line becomes a plain dashed rule rather
|
|
525
|
-
than overflowing.
|
|
526
567
|
- The rule is installed only in interactive (`tui`) sessions; RPC, JSON, and
|
|
527
568
|
print sessions append nothing.
|
|
528
569
|
- Separators recorded by the retired `turn-separator` extension are not
|
|
529
570
|
rendered, and `PI_DISABLED_EXTENSIONS=turn-separator` no longer affects the
|
|
530
571
|
rule; disable the whole extension with `bytefly` instead.
|
|
531
|
-
- There is no runtime command; the glyph, label prefix, padding,
|
|
532
|
-
tuned in
|
|
572
|
+
- There is no runtime command; the glyph, label prefix, padding, colors, and
|
|
573
|
+
minimum duration are tuned in
|
|
574
|
+
[`separator/config.ts`](./separator/config.ts).
|
|
533
575
|
|
|
534
576
|
## The control center
|
|
535
577
|
|
|
578
|
+
<img src="../../assets/bytefly.png" alt="The /bytefly control center: the Extensions and Settings section bar with the `Global · 10 extensions · 2 off · 1 missing` counts, one checkbox row per extension with its verdict, the focused extension's report, and the key hints" width="100%">
|
|
579
|
+
|
|
536
580
|
`/bytefly [extension] [refresh]` opens the control center on **Extensions**: a
|
|
537
581
|
keyboard-driven dock list of every extension Pi resolves for the session, so the
|
|
538
582
|
list matches what actually loads. `←`/`→` switch to **Settings**, where the same
|
|
@@ -544,7 +588,7 @@ when the row is switched off in settings, `env disabled` when
|
|
|
544
588
|
glyph and summary. The screen is drawn from the design system: a label-first
|
|
545
589
|
`bytefly ────` title rule,
|
|
546
590
|
the `Extensions · Settings` section bar beside the section's counts, one row
|
|
547
|
-
grammar (`❯ ◼
|
|
591
|
+
grammar (`❯ ◼ name … summary`), and the shared `◼` / `◻` checkbox.
|
|
548
592
|
`/bytefly doctor [extension] [refresh]` selects the doctor report, the same text
|
|
549
593
|
the `run_doctor` tool returns; in `tui` it opens the same screen. `[extension]`
|
|
550
594
|
narrows the Extensions section to one extension and `refresh` forces the first
|
|
@@ -568,12 +612,13 @@ installs or fetches a package.
|
|
|
568
612
|
manages the list is never a selectable row; its doctor report still appears in
|
|
569
613
|
the trailing `Not resolved` group.
|
|
570
614
|
- Shows whether each one is enabled (`◼`) or disabled (`◻`) in settings.
|
|
571
|
-
- Gives each row one verdict from the doctor's report: the worst severity
|
|
572
|
-
|
|
573
|
-
instead, because it will not load; a row the session's
|
|
615
|
+
- Gives each row one verdict from the doctor's report: the worst severity's
|
|
616
|
+
glyph (`!` degraded, `✕` missing) and its summary. A row that is `◻` reads
|
|
617
|
+
`off` instead, because it will not load; a row the session's
|
|
574
618
|
`PI_DISABLED_EXTENSIONS` excludes reads `env disabled`, so the two axes cannot
|
|
575
|
-
contradict each other.
|
|
576
|
-
|
|
619
|
+
contradict each other. The glyph marks what needs attention, so a row with
|
|
620
|
+
nothing to report — a clean report or none at all — leaves the glyph column
|
|
621
|
+
blank and says `ok` in words when a report exists.
|
|
577
622
|
- Toggles the focused extension with `Space`, writing `+pattern` / `-pattern`
|
|
578
623
|
into `extensions` (and package filter objects) in the active scope. A row in
|
|
579
624
|
the trailing `Not resolved` group has no pattern to write, so `Space` says so
|
|
@@ -597,11 +642,11 @@ installs or fetches a package.
|
|
|
597
642
|
without leaving the session.
|
|
598
643
|
|
|
599
644
|
**Settings.** The second section uses the same frame and the same `Tab` scope
|
|
600
|
-
switch, with its own cursor. It lists
|
|
645
|
+
switch, with its own cursor. It lists twenty-nine preferences in ten groups:
|
|
601
646
|
|
|
602
647
|
```
|
|
603
648
|
bytefly ──────────────────────────────────────────────────────────────
|
|
604
|
-
Extensions · Settings Global ·
|
|
649
|
+
Extensions · Settings Global · 29 settings
|
|
605
650
|
|
|
606
651
|
Startup (1)
|
|
607
652
|
❯ ◻ Bytefly startup TUI Off
|
|
@@ -620,16 +665,33 @@ bytefly ────────────────────────
|
|
|
620
665
|
Currency CNY (¥)
|
|
621
666
|
Cost decimals 2
|
|
622
667
|
Session budget 0
|
|
623
|
-
Transcript (
|
|
668
|
+
Transcript (3)
|
|
624
669
|
Rail glyph ╎
|
|
670
|
+
Achieved goal Hide
|
|
625
671
|
Output padding 1
|
|
626
|
-
Terminal (
|
|
672
|
+
Terminal (2)
|
|
673
|
+
Theme system
|
|
627
674
|
◻ Hardware cursor Off
|
|
675
|
+
Worktree (4)
|
|
676
|
+
◼ Fetch remote On
|
|
677
|
+
Base ref Fresh
|
|
678
|
+
Branch prefix worktree-
|
|
679
|
+
Prune after (days) 7
|
|
680
|
+
Snapshots (3)
|
|
681
|
+
◼ Automatic snapshots On
|
|
682
|
+
Snapshots kept 20
|
|
683
|
+
◼ Safety snapshot On
|
|
684
|
+
Jobs and watchers (3)
|
|
685
|
+
◻ Wake when a job finishes Off
|
|
686
|
+
◻ Keep jobs after exit Off
|
|
687
|
+
◻ Wake on a match Off
|
|
688
|
+
Memory (1)
|
|
689
|
+
◼ Inject notes On
|
|
628
690
|
Bytefly startup TUI — Pi setting
|
|
629
691
|
Use bytefly's startup header in place of Pi's startup TUI.
|
|
630
692
|
Default · ~/.pi/agent/settings.json
|
|
631
693
|
|
|
632
|
-
Esc close · ←/→ · Space change · Tab scope ·
|
|
694
|
+
Esc close · ←/→ · Space change · Tab scope · u reset · J JSON · [ ] group
|
|
633
695
|
```
|
|
634
696
|
|
|
635
697
|
| Group | Row | Source | Values |
|
|
@@ -648,20 +710,54 @@ bytefly ────────────────────────
|
|
|
648
710
|
| Pricing | Cost decimals | `price.currency.decimals` | 0, 1, 2, 3, 4 |
|
|
649
711
|
| Pricing | Session budget | `price.budget` | Number, `0` = off |
|
|
650
712
|
| Transcript | Rail glyph | `chrome.rail` | Text, exactly one column |
|
|
713
|
+
| Transcript | Achieved goal | `goal.achieved` | Show, Hide |
|
|
651
714
|
| Transcript | Output padding | Pi `settings.json` | 0, 1 |
|
|
715
|
+
| Terminal | Theme | Pi `settings.json` (`theme`) | `system`, `bytefly-dark`, `bytefly-light` |
|
|
652
716
|
| Terminal | Hardware cursor | Pi `settings.json` | Off, On |
|
|
717
|
+
| Worktree | Base ref | `worktree.baseRef` | Fresh, Head |
|
|
718
|
+
| Worktree | Branch prefix | `worktree.branchPrefix` | Text, trimmed, required |
|
|
719
|
+
| Worktree | Fetch remote | `worktree.fetchRemote` | Off, On |
|
|
720
|
+
| Worktree | Prune after (days) | `worktree.pruneAfterDays` | Number, 0–3650 |
|
|
721
|
+
| Snapshots | Automatic snapshots | `rewind.autoSnapshots` | Off, On |
|
|
722
|
+
| Snapshots | Snapshots kept | `rewind.max` | Number, 0–1000 |
|
|
723
|
+
| Snapshots | Safety snapshot | `rewind.safetySnapshot` | Off, On |
|
|
724
|
+
| Jobs and watchers | Wake when a job finishes | `job.wakeOnFinish` | Off, On |
|
|
725
|
+
| Jobs and watchers | Keep jobs after exit | `job.detachedByDefault` | Off, On |
|
|
726
|
+
| Jobs and watchers | Wake on a match | `watch.wakeOnMatch` | Off, On |
|
|
727
|
+
| Memory | Inject notes | `memory.inject` | Off, On |
|
|
653
728
|
|
|
654
729
|
Choosing **Currency** also writes that currency's default precision. Both rows
|
|
655
730
|
stay editable afterwards, so the footer follows the explicit values.
|
|
656
731
|
|
|
732
|
+
The **Theme** row lists `system` first, then the palettes this package ships,
|
|
733
|
+
`bytefly-dark` and `bytefly-light`; it cycles no further, so a bytefly screen
|
|
734
|
+
never proposes a palette it cannot vouch for. It writes the personal `theme`
|
|
735
|
+
setting and takes effect after reload. A value chosen elsewhere — Pi's built-in
|
|
736
|
+
`dark`, another package's theme, or an automatic pair such as
|
|
737
|
+
`bytefly-light/bytefly-dark` — is shown as stored (the pair with `… (automatic)`)
|
|
738
|
+
and is replaced by the next choice here, so manage those in Pi's `/settings` →
|
|
739
|
+
**Theme**.
|
|
740
|
+
|
|
657
741
|
`Space` (or `Enter`) changes the focused row: a boolean toggles, an enum cycles
|
|
658
742
|
forward, and a text row opens an inline editor on its value — the notification
|
|
659
|
-
title, the probe timeout, and the rail glyph.
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
743
|
+
title, the probe timeout, the branch prefix, and the rail glyph. `u` deletes the
|
|
744
|
+
focused row's key so its default applies again (`Already at its default.` when
|
|
745
|
+
nothing is stored in that scope; an inherited Project value says so instead),
|
|
746
|
+
`J` swaps the detail pane for the focused row's whole section as the active
|
|
747
|
+
scope stores it — the only view of the keys this screen leaves to JSON — and
|
|
748
|
+
`[` / `]` jump to the previous or next group. The detail pane names
|
|
749
|
+
the source, describes the preference, and shows
|
|
750
|
+
where the value comes from — `Global · ~/.pi/agent/bytefly.json`, `Project ·
|
|
751
|
+
.pi/bytefly.json`, `Inherited from Global · ~/.pi/agent/bytefly.json`, or
|
|
752
|
+
`Default · <the active scope's file>`; an app row names the personal
|
|
753
|
+
`settings.json`. A successful change marks the screen `Saved · reload to apply`
|
|
754
|
+
— even when the terminal is too short for the detail body — and closing offers
|
|
755
|
+
the same reload confirm as an extension toggle.
|
|
756
|
+
|
|
757
|
+
Six of the ten `bytefly.json` sections belong to other extensions. The screen
|
|
758
|
+
cannot import their normalizers, so it reports the leaf as the file states it and
|
|
759
|
+
declares the loader's default; `test/settings-coverage.test.ts` holds the
|
|
760
|
+
catalogue to every loader's defaults and bounds in both directions.
|
|
665
761
|
|
|
666
762
|
**Bytefly startup TUI** is the one row whose label differs from the Pi key it
|
|
667
763
|
writes: On writes `"quietStartup": true` (bytefly's header replaces Pi's startup
|
|
@@ -671,17 +767,18 @@ with `true` or `false`.
|
|
|
671
767
|
|
|
672
768
|
App rows are **Global only**: Pi's setters for them write the personal
|
|
673
769
|
`settings.json`, and only resource paths have public project setters. Project
|
|
674
|
-
scope therefore lists the
|
|
770
|
+
scope therefore lists the twenty-five `bytefly.json` rows and a
|
|
675
771
|
`App settings are Global only.` note rather than promising a write that cannot
|
|
676
772
|
happen. A `bytefly.json` row writes one leaf in the selected scope (a depth-1
|
|
677
773
|
key, or a nested one such as `price.currency.decimals`) through a per-key
|
|
678
774
|
writer, so every sibling key, section, `$schema`, and `version` is preserved. A
|
|
679
|
-
malformed document is refused with a notice instead of overwritten
|
|
775
|
+
malformed document is refused with a notice instead of overwritten, and `u`
|
|
776
|
+
removes that one leaf through the same writer's `unsetConfigValueAt`.
|
|
680
777
|
|
|
681
778
|
The non-`tui` form prints the headline, the groups, and `Label: Value` rows:
|
|
682
779
|
|
|
683
780
|
```
|
|
684
|
-
bytefly: Settings · Global ·
|
|
781
|
+
bytefly: Settings · Global · 29 settings
|
|
685
782
|
|
|
686
783
|
Startup (1)
|
|
687
784
|
Bytefly startup TUI: Off
|
|
@@ -733,6 +830,9 @@ headline; a named extension prints its full findings instead.
|
|
|
733
830
|
| `Space` | Toggle the focused extension (Extensions); change the focused setting (Settings), or open the editor on a text row. |
|
|
734
831
|
| `x` | Clear the focused extension's project override (Extensions, Project scope). |
|
|
735
832
|
| `Enter` | Expand or collapse the focused extension's findings (Extensions); change the focused setting, or open the editor on a text row (Settings). |
|
|
833
|
+
| `u` | Delete the focused setting's key so its default applies again (Settings, `bytefly.json` rows). |
|
|
834
|
+
| `J` | Show or hide the focused row's whole section as stored (Settings, `bytefly.json` rows). |
|
|
835
|
+
| `[` / `]` | Jump to the previous or next group (Settings). |
|
|
736
836
|
| `←` / `→`, `Home` / `End` (`Ctrl+A` / `Ctrl+E`) | Move the editor's caret while a text row is being edited. |
|
|
737
837
|
| `Backspace` / `Delete`, `Ctrl+U` | Edit the buffer: delete a character, or clear it. |
|
|
738
838
|
| `Enter` / `Esc` (editing) | Save the buffer, or cancel and restore the stored value. |
|
|
@@ -824,10 +924,11 @@ control-free line before it reaches an escape sequence or a shell argument.
|
|
|
824
924
|
|
|
825
925
|
## Update check
|
|
826
926
|
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
927
|
+
Pi's package manager already knows which configured packages are behind, so
|
|
928
|
+
bytefly does not keep a second detector. Once per interactive session, in the
|
|
929
|
+
background, it asks the captured `checkForAvailableUpdates` for the package list,
|
|
930
|
+
suppresses Pi's own `Package Updates Available` block, and draws one notice for
|
|
931
|
+
every row Pi returned.
|
|
831
932
|
|
|
832
933
|
```
|
|
833
934
|
█▀█ Pi v1.3.0
|
|
@@ -835,47 +936,50 @@ reports it once, in the two places it already owns:
|
|
|
835
936
|
```
|
|
836
937
|
|
|
837
938
|
```
|
|
838
|
-
bytefly ·
|
|
839
|
-
╎ ◌
|
|
939
|
+
bytefly · 2 package updates available
|
|
940
|
+
╎ ◌ @gavin-hu/my-pi-agent · v0.11.4 → v0.12.0
|
|
941
|
+
╎ ◌ some-other-package · project
|
|
840
942
|
╎ ◌ update · pi update --extensions
|
|
841
943
|
╎ ◌ release · https://github.com/gavin-hu/my-pi-agent/releases/tag/v0.12.0
|
|
842
944
|
```
|
|
843
945
|
|
|
844
|
-
The marker is the shared `↑` glyph and
|
|
845
|
-
wide, so the header's column math is unchanged — painted with the
|
|
846
|
-
`accent` role: an action rather than a warning, so the muted version
|
|
847
|
-
stays quiet and the transcript is not turned yellow for a normal state.
|
|
848
|
-
|
|
849
|
-
|
|
946
|
+
The marker is the shared `↑` glyph and this package's newest version — the arrow
|
|
947
|
+
is one cell wide, so the header's column math is unchanged — painted with the
|
|
948
|
+
header's `accent` role: an action rather than a warning, so the muted version
|
|
949
|
+
beside it stays quiet and the transcript is not turned yellow for a normal state.
|
|
950
|
+
Other packages never change the header. The marker is part of the chrome cell, so
|
|
951
|
+
the two identity cells still line up, and it is the first thing the identity
|
|
952
|
+
sheds when the terminal narrows.
|
|
850
953
|
|
|
851
954
|
The notice is the shared transcript block: the `bytefly · title` headline at the
|
|
852
|
-
margin,
|
|
955
|
+
margin, one rail row per package with this package's version arrow or the other
|
|
956
|
+
package's scope, then the fixing command and this package's release URL, all at
|
|
853
957
|
`info` severity because nothing is broken. It stays in scrollback and the model
|
|
854
|
-
reads the same
|
|
855
|
-
|
|
856
|
-
The
|
|
857
|
-
|
|
858
|
-
registry
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
Past the window the check runs again and rewrites the entry; a failed
|
|
869
|
-
nothing, so the next session tries again. Offline, the cached
|
|
870
|
-
no request and no
|
|
871
|
-
available and the
|
|
872
|
-
|
|
873
|
-
`/bytefly update` is the on-demand half: it ignores the window,
|
|
874
|
-
now, records and paints the result, and prints one line —
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
set)`, or `could not
|
|
878
|
-
|
|
958
|
+
reads the same names, version, command, and URL in plain text.
|
|
959
|
+
|
|
960
|
+
The list is Pi's decision: npm ranges, git refs, project scope, a missing
|
|
961
|
+
install, and `PI_OFFLINE` all follow its package manager. The only extra read is
|
|
962
|
+
`GET https://registry.npmjs.org/@gavin-hu%2Fmy-pi-agent/latest` when Pi reports
|
|
963
|
+
this package, used just to name the version arrow and release URL. A failed
|
|
964
|
+
version read drops those two pieces but keeps the package list and command.
|
|
965
|
+
|
|
966
|
+
The answer is cached in `<agentDir>/bytefly/update.json` as the package list,
|
|
967
|
+
this package's optional version, the time it was read, and a key over the cwd and
|
|
968
|
+
the effective package sources. A session that starts inside the 24-hour window
|
|
969
|
+
reuses that snapshot — painting the marker and posting the notice from it —
|
|
970
|
+
without repeating Pi's npm/git checks, so a working day of sessions costs one
|
|
971
|
+
read. A project switch or a package install/removal changes the key and forces a
|
|
972
|
+
fresh read. Past the window the check runs again and rewrites the entry; a failed
|
|
973
|
+
read writes nothing, so the next session tries again. Offline, the cached marker
|
|
974
|
+
is used with no request and no notice, because a stale version is still the best
|
|
975
|
+
answer available and the list itself is advisory.
|
|
976
|
+
|
|
977
|
+
`/bytefly update` is the on-demand half: it ignores the window, asks Pi's package
|
|
978
|
+
manager now, records and paints the result, and prints one line — the package
|
|
979
|
+
list with this package's version and release URL when known, `up to date — no
|
|
980
|
+
configured package has an update`, `the update check was skipped (PI_OFFLINE is
|
|
981
|
+
set)`, or `could not check package updates`. It resolves no packages, probes no
|
|
982
|
+
extension, and posts no second notice, so a session open for days can see a
|
|
879
983
|
release without a restart. Opening the control center never checks: the screen has
|
|
880
984
|
no update surface, and the only request paths are `session_start` and this
|
|
881
985
|
command.
|
|
@@ -887,9 +991,16 @@ command.
|
|
|
887
991
|
rule, and transcript renderers stay on. Use `PI_DISABLED_EXTENSIONS=bytefly`
|
|
888
992
|
(or `pi config`) to turn off all of bytefly.
|
|
889
993
|
- **App settings are Global only.** Pi's setters for preferences such as
|
|
890
|
-
`quietStartup` (the **Bytefly startup TUI** row), `outputPad`,
|
|
891
|
-
`showHardwareCursor` write the personal `settings.json`; the
|
|
892
|
-
those rows in Project scope rather than writing a file Pi cannot
|
|
994
|
+
`quietStartup` (the **Bytefly startup TUI** row), `outputPad`,
|
|
995
|
+
`showHardwareCursor`, and `theme` write the personal `settings.json`; the
|
|
996
|
+
screen hides those rows in Project scope rather than writing a file Pi cannot
|
|
997
|
+
manage.
|
|
998
|
+
- **The Theme row offers only this package's palettes.** `system`,
|
|
999
|
+
`bytefly-dark`, and `bytefly-light` are the whole cycle; Pi's built-ins and any
|
|
1000
|
+
user, project, or other package's theme stay in Pi's `/settings` → **Theme**,
|
|
1001
|
+
and a value set there shows as stored here. An automatic pair such as
|
|
1002
|
+
`bytefly-light/bytefly-dark` shows as stored but is replaced by the next single
|
|
1003
|
+
choice, and the change applies after a reload like the other app rows.
|
|
893
1004
|
- **Project overrides of app settings are not shown.** App rows read the
|
|
894
1005
|
personal file; a `.pi/settings.json` override still wins at runtime, and
|
|
895
1006
|
`pi config` is the place to manage it.
|
|
@@ -909,19 +1020,22 @@ command.
|
|
|
909
1020
|
their authoritative names are not exposed to extensions. Use `pi config`.
|
|
910
1021
|
- **Packages are not installed, removed, or updated here**; use `pi install`,
|
|
911
1022
|
`pi remove`, and `pi update`.
|
|
912
|
-
- **The update
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1023
|
+
- **The update list is Pi's.** Only packages configured in `settings.json` are
|
|
1024
|
+
checked; `pi -e .`, a temporary checkout, and other unmanaged loads get no
|
|
1025
|
+
update prompt. The version arrow and release URL still come from npm's
|
|
1026
|
+
`latest`, so a private registry or a version published under another tag can
|
|
1027
|
+
lose those two pieces while the list stays correct.
|
|
916
1028
|
- **The cache window is fixed at 24 hours.** It runs at `session_start` in `tui`
|
|
917
|
-
mode and reuses
|
|
918
|
-
`/bytefly` and `doctor` do not
|
|
919
|
-
|
|
1029
|
+
mode and reuses a snapshot younger than that whose key matches the cwd and
|
|
1030
|
+
package sources; there is no setting for it, and `/bytefly` and `doctor` do not
|
|
1031
|
+
report the version. A failed or slow background request is retried by the next
|
|
1032
|
+
session, or immediately by `/bytefly update`.
|
|
920
1033
|
- **The marker needs the bytefly startup TUI.** It lives on the custom header,
|
|
921
1034
|
so with `quietStartup` off the notice is the whole signal.
|
|
922
|
-
- **Pi
|
|
923
|
-
|
|
924
|
-
|
|
1035
|
+
- **Pi's block is suppressed by a host shim.** bytefly wraps
|
|
1036
|
+
`DefaultPackageManager.prototype.checkForAvailableUpdates` at `session_start`
|
|
1037
|
+
and restores it on shutdown. A future Pi that changes that method shape makes
|
|
1038
|
+
the shim inert, and Pi's own block can come back.
|
|
925
1039
|
- **No auto-update, and the release URL is text only.** The notice names a
|
|
926
1040
|
command instead of running one, and the notice renderer cannot open a link, so
|
|
927
1041
|
the release row prints the URL and nothing more — no changelog body, no way to
|
|
@@ -966,6 +1080,9 @@ command.
|
|
|
966
1080
|
- **Notifications are not focus-aware.** They fire whether or not the terminal
|
|
967
1081
|
has focus, and once per trigger rather than once per unseen event. There is
|
|
968
1082
|
no focus API to consult.
|
|
1083
|
+
- **`/compact` is Pi's block.** The summary component is built in, so bytefly
|
|
1084
|
+
cannot render, hide, or shorten it; the themes only choose its fill and label
|
|
1085
|
+
color. Branch summaries and skill invocations share the same theme tokens.
|
|
969
1086
|
- **A background job cannot ask for input.** The `needsInput` trigger is a
|
|
970
1087
|
prompt raised during a run, not a process waiting on stdin: jobs are
|
|
971
1088
|
fire-and-observe, so that state does not exist.
|
|
@@ -973,11 +1090,11 @@ command.
|
|
|
973
1090
|
host lacks (or an OSC method off a TTY) and the notification is dropped; only
|
|
974
1091
|
`auto` inspects the environment. `doctor` now reports the mismatch as a
|
|
975
1092
|
`degraded` finding, which says what to change but does not fix it for you.
|
|
976
|
-
- **The working
|
|
1093
|
+
- **The working line is one global row.** `setWorkingMessage` drives the
|
|
977
1094
|
single working row, so bytefly and any other extension setting it race — last
|
|
978
1095
|
writer wins — and the message is reset to Pi's default at `agent_end`. If the
|
|
979
|
-
row is hidden (`ctx.ui.setWorkingVisible(false)`) the
|
|
980
|
-
and a reload mid-run does not resume
|
|
1096
|
+
row is hidden (`ctx.ui.setWorkingVisible(false)`) the line has no surface,
|
|
1097
|
+
and a reload mid-run does not resume the count until the next turn.
|
|
981
1098
|
|
|
982
1099
|
## Non-goals
|
|
983
1100
|
|
|
@@ -1001,7 +1118,7 @@ command.
|
|
|
1001
1118
|
match — are the whole surface.
|
|
1002
1119
|
- No sound, action buttons, notification history, or de-duplication; a
|
|
1003
1120
|
notification is a fire-and-forget message, not an inbox.
|
|
1004
|
-
- No frozen per-run working duration: the
|
|
1121
|
+
- No frozen per-run working duration: the line is live and is handed back to
|
|
1005
1122
|
Pi when the working row comes down, because the extension API exposes no hook
|
|
1006
1123
|
to keep a finished run's total.
|
|
1007
1124
|
|
|
@@ -1014,26 +1131,26 @@ rather than showing a wrong value.
|
|
|
1014
1131
|
|
|
1015
1132
|
| Integration point | Details |
|
|
1016
1133
|
|---|---|
|
|
1017
|
-
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **Bytefly startup TUI** row). `false`, `"header"`, and unset call `setHeader(undefined)`, leaving Pi's built-in header in place. The nameplate insets by Pi's `outputPad` (read through `pi.getSettings()`), so it sits on the transcript margin, and the help hangs one body indent inside it. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. The chrome version gains `↑<latest>` from the `UpdateSource`, and `registerHeader` returns a `refresh()` handle that re-installs the last context's header when that value arrives. |
|
|
1134
|
+
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"` and `pi.getSettings().quietStartup === true` (the **Bytefly startup TUI** row). `false`, `"header"`, and unset call `setHeader(undefined)`, leaving Pi's built-in header in place. The nameplate insets by Pi's `outputPad` (read through `pi.getSettings()`), so it sits on the transcript margin, and the help hangs one body indent inside it. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. The factory reads `tui.terminal.rows` on every render, so the height ladder in `header/config.ts` sheds help groups and then the leading blank row as the terminal shortens (unknown height keeps the full header). The chrome version gains `↑<latest>` from the `UpdateSource`, and `registerHeader` returns a `refresh()` handle that re-installs the last context's header when that value arrives. |
|
|
1018
1135
|
| Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
|
|
1019
1136
|
| 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. |
|
|
1020
1137
|
| 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`. `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. |
|
|
1021
1138
|
| 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. |
|
|
1022
1139
|
| Screen command | `pi.registerCommand("bytefly")` takes `[doctor] [settings] [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, `run_doctor`'s report for `doctor`, or the grouped settings listing with values for `settings`. A named extension is checked against the discovered set before any probe. Tab completes the subcommands, extension names after `doctor`, and `refresh`; `/bytefly settings` rejects a name. |
|
|
1023
|
-
| Turn separator | `registerEntryRenderer("bytefly-separator")` draws each
|
|
1024
|
-
| Working
|
|
1140
|
+
| Turn separator | `registerEntryRenderer("bytefly-separator")` draws each stored receipt; `agent_start` opens it, top-level `tool_execution_start`/`tool_execution_end` count tools and failures, and `agent_settled` appends `pi.appendEntry("bytefly-separator", { turn, durationMs, tools, failures, aborted })` in `tui` mode only. The receipt fields are omitted when no `agent_start` was seen, so an older or partially observed entry stays `{ turn }`. |
|
|
1141
|
+
| Working line | `turn_start` starts a 1s tick that drives `ctx.ui.setWorkingMessage` in `tui` mode; before a tool runs the message is `Working… Ns`, and each top-level `tool_execution_start` repaints it as `tool · N tools · Ns` (nested calls carrying `parentToolCallId` are skipped). `agent_end` restores Pi's default and cancels the tick (also on `session_shutdown`). No config file and no persisted state; the count lives in the register's closure. |
|
|
1025
1142
|
| 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. |
|
|
1026
1143
|
| Picker discovery | `SettingsManager.create(...)` plus `DefaultPackageManager.resolve({ onMissing: "skip" })`, both public exports; both views drop `bytefly`'s own entrypoint. |
|
|
1027
1144
|
| Picker writes | `SettingsManager` setters (`setExtensionPaths`, `setPackages`, `setProjectExtensionPaths`, `setProjectPackages`) then `flush()`; `ctx.reload()` after the screen closes when changes are pending. |
|
|
1028
|
-
| Settings writes | App rows call `SettingsManager` setters (`setQuietStartup`, `setOutputPad`, `setShowHardwareCursor`) on the global store and `flush()`, then surface `drainErrors()`; `bytefly.json` rows call `
|
|
1145
|
+
| Settings writes | App rows call `SettingsManager` setters (`setQuietStartup`, `setOutputPad`, `setShowHardwareCursor`, `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. |
|
|
1029
1146
|
| 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. |
|
|
1030
1147
|
| 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. |
|
|
1031
1148
|
| 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. |
|
|
1032
|
-
| Update check | `session_start` in `tui` mode reads `<agentDir>/bytefly/update.json
|
|
1149
|
+
| Update check | `session_start` in `tui` mode installs a suppression on `DefaultPackageManager.prototype.checkForAvailableUpdates`, then reads `<agentDir>/bytefly/update.json`. A fresh entry whose key matches the cwd and effective package sources is recorded without a package-manager call; otherwise bytefly fires `fetchAvailableUpdates()` without awaiting, resolves this package's version through `fetchLatestVersion()` when Pi reports it, writes the snapshot, and records it. `onUpdate` re-installs the header, and `pi.sendMessage(updateNotice(...))` posts the one notice with its version arrow and release URL. `PI_OFFLINE` paints the cached marker only. `/bytefly update` calls the returned `UpdateHandle.recheck()`, which bypasses the window and returns an `UpdateOutcome`; a generation counter drops a background reply that lands after `session_shutdown`, a per-load flag keeps it to one announcement, and shutdown restores Pi's method. |
|
|
1033
1150
|
| 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. |
|
|
1034
1151
|
| Data sources | `footerData.getGitBranch()`, `footerData.getAvailableProviderCount()`, `ctx.getContextUsage()`, `ctx.sessionManager.getEntries()`, `ctx.sessionManager.getSessionName()`, `ctx.model`; subscribes to `footerData.onBranchChange` to repaint. |
|
|
1035
|
-
| State storage | None besides the inert separator entries. The footer reads session entries and the price config (a memoized scan) and writes no tool-result `details`; it appends `bytefly-separator` entries excluded from LLM context. The screen derives its view from the picker runtime and the current reports, and persists extension toggles through `settings.json`. The Settings section derives from a snapshot of the personal `settings.json` and both `bytefly.json` documents, and persists through the same `SettingsManager` setters or the per-leaf `bytefly.json` writer. Doctor's findings are session-scoped in memory only — cached for the session, never written to the session or a file. Notify holds only the config and the run-active flag in its closure. The update check holds
|
|
1036
|
-
| Lifecycle | `session_start` installs the header when Pi's `quietStartup` is `true` and the footer, loads the chrome rail glyph, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on and `quietStartup` is `true`, loads the notify config and subscribes to the job bus, and starts the
|
|
1152
|
+
| State storage | None besides the inert separator entries. The footer reads session entries and the price config (a memoized scan) and writes no tool-result `details`; it appends `bytefly-separator` entries excluded from LLM context. The screen derives its view from the picker runtime and the current reports, and persists extension toggles through `settings.json`. The Settings section derives from a snapshot of the personal `settings.json` and both `bytefly.json` documents, and persists through the same `SettingsManager` setters or the per-leaf `bytefly.json` writer. Doctor's findings are session-scoped in memory only — cached for the session, never written to the session or a file. Notify holds only the config and the run-active flag in its closure. The update check holds this package's version in the per-load `UpdateSource` and one project-scoped snapshot in `<agentDir>/bytefly/update.json`. |
|
|
1153
|
+
| Lifecycle | `session_start` installs the header when Pi's `quietStartup` is `true` and the footer, loads the chrome rail glyph, points the doctor runtime at the session cwd, probes the extensions with hard requirements when `bytefly.json`'s `doctor.proactive` is on and `quietStartup` is `true`, loads the notify config and subscribes to the job bus, and starts the package-update check; `session_tree` reinstalls the header and footer and reloads the rail; `session_shutdown` restores Pi's built-in header, footer, and package-update method, disposes the branch subscription, drops doctor's cached findings, drops the notify bus subscription, and clears the recorded version. |
|
|
1037
1154
|
|
|
1038
1155
|
## Design notes
|
|
1039
1156
|
|
|
@@ -1075,8 +1192,12 @@ rather than showing a wrong value.
|
|
|
1075
1192
|
expand toggle, so no themed string outlives its theme. `indentBlockLines` only
|
|
1076
1193
|
measures a line it cannot prove fits, and the header memoizes on the width,
|
|
1077
1194
|
theme, shape, and the help chords it prints, so a live rebind still repaints.
|
|
1078
|
-
|
|
1079
|
-
|
|
1195
|
+
`SeparatorComponent` uses the same memo for its full-width rule, so a long
|
|
1196
|
+
session does not repaint every turn's rule each frame. The footer's context
|
|
1197
|
+
estimate and session name join its pricing scan in the leaf-keyed memo: all
|
|
1198
|
+
three are O(session) work the host recomputes from scratch, and
|
|
1199
|
+
`createRateLookup` compiles the rate table once per config instead of once per
|
|
1200
|
+
record.
|
|
1080
1201
|
- **The frame delegates; it does not re-render.** Pi resolves tool renderers
|
|
1081
1202
|
through the extension chain, and the resolved object is the definition the row
|
|
1082
1203
|
reads, so a resolver can override `renderShell` and wrap `next()`'s
|
|
@@ -1110,7 +1231,8 @@ rather than showing a wrong value.
|
|
|
1110
1231
|
themselves by that pad: the tool frame and the notice take it from Pi, and the
|
|
1111
1232
|
turn separator reads the last value a sibling observed (`pad.ts`). Pi's setting
|
|
1112
1233
|
is the only knob — bytefly adds no padding of its own. The footer's group
|
|
1113
|
-
separator
|
|
1234
|
+
separator draws `│` between chips — a divider, not the rail (`╎`), which stays
|
|
1235
|
+
a transcript-only glyph.
|
|
1114
1236
|
- **The header is a nameplate, not a dashboard.** Pi's built-in brand colors are
|
|
1115
1237
|
fixed, so the mark ignores the active theme; bytefly's header draws a two-tone
|
|
1116
1238
|
mark from the `accent`/`warn` roles, a signature rule whose accent lead sits
|
|
@@ -1118,8 +1240,10 @@ rather than showing a wrong value.
|
|
|
1118
1240
|
and a grouped help block. It takes its margin from Pi's `outputPad`, like the
|
|
1119
1241
|
tool frame and the notice, and hangs the help one body indent inside it, so the
|
|
1120
1242
|
header follows a non-default pad instead of assuming a column. It adds no
|
|
1121
|
-
session or model data — that is the footer's job — and
|
|
1122
|
-
|
|
1243
|
+
session or model data — that is the footer's job — and its shape follows the
|
|
1244
|
+
terminal: the height ladder drops whole help groups, then the leading blank
|
|
1245
|
+
row, before the nameplate gives up anything, so a short pane spends its rows
|
|
1246
|
+
on the transcript instead of chrome.
|
|
1123
1247
|
- **Two lines, four zones.** Line 1 is identity (`pwd` left, branch + worktree
|
|
1124
1248
|
right); line 2 is resources (meters left, model + level right). This keeps
|
|
1125
1249
|
"where am I / what state" separate from "how much am I burning".
|
|
@@ -1129,7 +1253,7 @@ rather than showing a wrong value.
|
|
|
1129
1253
|
dispatching process and the delegated work stays visible beside it.
|
|
1130
1254
|
- **The gauge is anchored at column 0.** A leading mode slot would shift the
|
|
1131
1255
|
context percentage left and right as plan mode came and went; trailing it
|
|
1132
|
-
after a
|
|
1256
|
+
after a `│` keeps the percentage in a fixed place while the mode stays
|
|
1133
1257
|
visible as the meters drop.
|
|
1134
1258
|
- **Statuses are routed, not repeated.** The built-in footer renders every
|
|
1135
1259
|
`setStatus` value on its own line, so the bar sorts them by meaning instead:
|
|
@@ -1147,9 +1271,9 @@ rather than showing a wrong value.
|
|
|
1147
1271
|
non-zero usage, so it reads full only at 100% and a small percentage never
|
|
1148
1272
|
disappears; unknown usage draws no gauge at all. Only at extreme widths does
|
|
1149
1273
|
`truncateToWidth` clip the remaining text.
|
|
1150
|
-
- **Separators shrink to a single space.** Padded separators (` · `, `
|
|
1274
|
+
- **Separators shrink to a single space.** Padded separators (` · `, ` │ `)
|
|
1151
1275
|
collapse to one space before `truncateToWidth` applies, so adjacent segments
|
|
1152
|
-
never collide and the ellipsis never replaces a
|
|
1276
|
+
never collide and the ellipsis never replaces a `│` with nothing after it.
|
|
1153
1277
|
- **Statuses compact with their colour.** A themed status's compact icon form
|
|
1154
1278
|
reattaches its opening and closing SGR sequences around the visible text, so a
|
|
1155
1279
|
red `✗1` stays red instead of losing its colour exactly when the bar tightens.
|
|
@@ -1253,32 +1377,38 @@ rather than showing a wrong value.
|
|
|
1253
1377
|
- **The prerequisite table is data.** No I/O, no host access, no module state:
|
|
1254
1378
|
every probe dependency arrives as a seam, so `probeExtension` is testable with
|
|
1255
1379
|
no process and `lib/` stays value-only.
|
|
1256
|
-
- **
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1380
|
+
- **Pi owns the update list; bytefly owns the look.** There is one detector, not
|
|
1381
|
+
two: `DefaultPackageManager` already resolves npm ranges, git refs, project
|
|
1382
|
+
scope, and offline mode, and bytefly only carries its result to a themed
|
|
1383
|
+
surface. The extra registry read only names this package's version for the
|
|
1384
|
+
marker, arrow, and release URL; it never decides whether an update exists.
|
|
1385
|
+
- **The suppression is a host shim, not a second checker.** Pi has no setting or
|
|
1386
|
+
extension event for its startup block, so bytefly replaces the public method
|
|
1387
|
+
that feeds it while keeping the captured original for its own read. It is
|
|
1388
|
+
installed only in `tui`, restored on shutdown, and made inert if the host
|
|
1389
|
+
changes shape.
|
|
1390
|
+
- **The marker is an action, the notice is information.** This package's new
|
|
1391
|
+
version is drawn in the accent on the header, where it sits beside a control
|
|
1392
|
+
the user can act on, and every package is listed at `info` severity in the
|
|
1393
|
+
transcript, where a `warn` rail would say something is broken. Neither surface
|
|
1394
|
+
needs per-frame polling: the value arrives once, the memo key includes it, and
|
|
1395
|
+
one `setHeader` re-install repaints.
|
|
1267
1396
|
- **The transport stays local.** `web-access`'s runner does redirects, SSRF
|
|
1268
1397
|
checks, HTML extraction, and caching — none of it applies to one fixed JSON
|
|
1269
1398
|
endpoint, and an extension may not import another's modules, so the ~20-line
|
|
1270
|
-
read lives beside the check with the `fetch` and timeout as seams.
|
|
1399
|
+
read lives beside the check with the `fetch` and timeout as seams. The package
|
|
1400
|
+
list itself is Pi's own command execution, not a second transport.
|
|
1271
1401
|
|
|
1272
1402
|
## Files
|
|
1273
1403
|
|
|
1274
1404
|
The surfaces are folders: `header/`, `footer/` (the status bar and its price
|
|
1275
1405
|
calculation), `message/` (the user-message marker), `notice/` (the shared notice),
|
|
1276
1406
|
`block/` (the tool-block frame), `separator/`, `working/` (the live
|
|
1277
|
-
|
|
1407
|
+
run line on Pi's working row), `panel/` (the
|
|
1278
1408
|
unified screen and its merged model),
|
|
1279
1409
|
`picker/` (discovery and the settings store), `doctor/` (the `run_doctor` tool
|
|
1280
|
-
and its probe runtime), `notify/`, and `update/` (the
|
|
1281
|
-
|
|
1410
|
+
and its probe runtime), `notify/`, and `update/` (Pi's package list, the host
|
|
1411
|
+
suppression, the cache, and the header marker). The chrome and the screen are drawn from
|
|
1282
1412
|
the package's [`lib/tui/`](../../lib/tui/) design system (tokens, rules, rows,
|
|
1283
1413
|
columns, gauge), so the look follows the active theme.
|
|
1284
1414
|
|
|
@@ -1294,10 +1424,10 @@ columns, gauge), so the look follows the active theme.
|
|
|
1294
1424
|
| `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, status keys, labels. |
|
|
1295
1425
|
| `footer/types.ts` | `StatusSnapshot`, `Segment`, `LineSpec`, `UsageRecord`, and footer/TUI shapes. |
|
|
1296
1426
|
| `footer/collect/entries.ts` | Session entries → usage records, each resolved to the model in effect. |
|
|
1297
|
-
| `footer/collect/snapshot.ts` | Snapshot assembly; memoized pricing scan per branch leaf. |
|
|
1427
|
+
| `footer/collect/snapshot.ts` | Snapshot assembly; memoized pricing scan, context estimate, and session name per branch leaf. |
|
|
1298
1428
|
| `footer/price/types.ts` | `Currency`, `ModelRates`, `PeakWindow`/`PeakSchedule`, `ByteflyConfig`. |
|
|
1299
1429
|
| `footer/price/config.ts` | The `price` section of `bytefly.json`: schema, defaults, built-in DeepSeek rates/tariff, currency defaults, normalizer, loader. |
|
|
1300
|
-
| `footer/price/rates.ts` | Model-key matching: exact and wildcard
|
|
1430
|
+
| `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. |
|
|
1301
1431
|
| `footer/price/schedule.ts` | Peak-window parsing and evaluation in a configured zone. |
|
|
1302
1432
|
| `footer/price/price.ts` | Records → totals: rated cost in both modes, Pi's recorded cost as USD's fallback, and the peak multiplier. |
|
|
1303
1433
|
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd, the context role, truncation). |
|
|
@@ -1316,20 +1446,21 @@ columns, gauge), so the look follows the active theme.
|
|
|
1316
1446
|
| `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. |
|
|
1317
1447
|
| `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. |
|
|
1318
1448
|
| `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). |
|
|
1319
|
-
| `separator/config.ts` | Turn-rule tuning: `customType`, glyph, label prefix, padding, and roles. |
|
|
1320
|
-
| `separator/register.ts` | Registers the entry renderer and appends
|
|
1321
|
-
| `separator/component.ts` | `SeparatorComponent`: the
|
|
1322
|
-
| `separator/format.ts` | Pure `
|
|
1323
|
-
| `separator/types.ts` | `TurnSeparatorData
|
|
1324
|
-
| `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the
|
|
1325
|
-
| `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape. |
|
|
1326
|
-
| `working/register.ts` | Starts the tick on `turn_start` and cancels
|
|
1449
|
+
| `separator/config.ts` | Turn-rule tuning: `customType`, glyph, label prefix, padding, receipt minimum duration and outcome wording, and roles. |
|
|
1450
|
+
| `separator/register.ts` | Registers the entry renderer, tracks the run's tools and failures, and appends the receipt on `agent_settled`. |
|
|
1451
|
+
| `separator/component.ts` | `SeparatorComponent`: the entry renderer, memoized on the width so a repeat frame does not rebuild the rule. |
|
|
1452
|
+
| `separator/format.ts` | Pure `receiptLabel` (the width ladder), `receiptRole`, and `separatorLine`, drawn by the kit's `centeredRule`. |
|
|
1453
|
+
| `separator/types.ts` | `TurnSeparatorData`: the turn plus the optional receipt fields. |
|
|
1454
|
+
| `working/config.ts` | Counter tuning (`WORKING_CONFIG`): the words, the tool singular/plural, and the tick interval. |
|
|
1455
|
+
| `working/format.ts` | Pure `formatElapsed` (whole seconds) and the working-message shape: the plain count and the `tool · N tools · elapsed` run line. |
|
|
1456
|
+
| `working/register.ts` | Starts the tick on `turn_start`, tracks top-level tools on `tool_execution_start`, and cancels on `agent_end`/`session_shutdown`. |
|
|
1327
1457
|
| `panel/types.ts` | `PanelSection` (`extensions` | `settings`), `PanelRow`, and `PanelModel`, the merged row model. |
|
|
1328
1458
|
| `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering. |
|
|
1329
1459
|
| `panel/format.ts` | Non-TUI text: the extension headline and grouped listing with a per-row health suffix, plus the section segments, the Settings counts/headline, and the grouped Settings listing. |
|
|
1330
1460
|
| `panel/settings.ts` | The curated Settings catalogue: descriptors, snapshot views and origins, value cycling, stored-value mapping, validation, and grouping, plus the per-section readers that resolve a row's leaf over the global and project documents. |
|
|
1331
1461
|
| `panel/settings-runtime.ts` | The Settings runtime: snapshot cache, scope guards, app setters, per-leaf `bytefly.json` writes, dirty state, and change listeners. |
|
|
1332
|
-
| `panel/
|
|
1462
|
+
| `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. |
|
|
1463
|
+
| `panel/tui.ts` | `PanelComponent`, the two-section dock screen (Extensions list and Settings list) and its section composition; the editing key map is `tui/editing.ts` and the shared frame is `tui/frame.ts`. |
|
|
1333
1464
|
| `panel/commands.ts` | `/bytefly`: one command for the screen sections, the `doctor` report, the settings listing, and their text modes. |
|
|
1334
1465
|
| `picker/types.ts` | Picker host seams (`SettingsStore`, `ExtensionResolver`, `Discovery`), the app-settings setters, and row types. |
|
|
1335
1466
|
| `picker/resources.ts` | Pure grouping, labels, display names, and pattern helpers. |
|
|
@@ -1347,12 +1478,14 @@ columns, gauge), so the look follows the active theme.
|
|
|
1347
1478
|
| `notify/dispatch.ts` | Method selection and delivery: OSC 777/99, Windows toast, `osascript`, `notify-send`, over injected seams. |
|
|
1348
1479
|
| `notify/format.ts` | Pure notification text: session label and the turn / input / job / watch bodies. |
|
|
1349
1480
|
| `notify/register.ts` | Registers the four triggers, loads the config at `session_start`, and owns the job- and watch-bus subscriptions. |
|
|
1350
|
-
| `update/
|
|
1481
|
+
| `update/types.ts` | `PackageUpdate`, derived from Pi's public manager method, and `PackageUpdateCheck`. |
|
|
1482
|
+
| `update/suppress.ts` | The host shim: capture Pi's `checkForAvailableUpdates`, replace it with an empty result, and restore it on shutdown. |
|
|
1483
|
+
| `update/check.ts` | Pi's package list through `DefaultPackageManager`, plus the registry `GET` that names this package's version for the marker, arrow, and release URL. |
|
|
1351
1484
|
| `update/version.ts` | Pure semver parsing and `isNewerVersion`, including prerelease precedence. |
|
|
1352
|
-
| `update/state.ts` | `UpdateSource` and `createUpdateState` (
|
|
1353
|
-
| `update/cache.ts` | The
|
|
1354
|
-
| `update/format.ts` | `updateMarker`, `updateNotice`, `releaseUrl`, and `updateOutcomeText`: the header's `↑0.12.0`, the
|
|
1355
|
-
| `update/register.ts` | The lifecycle: the cache-first session-start read, the async
|
|
1485
|
+
| `update/state.ts` | `UpdateSource` and `createUpdateState` (this package's known version, one record per load), plus `UpdateOutcome`, the four answers an explicit re-check can give. |
|
|
1486
|
+
| `update/cache.ts` | The project-scoped snapshot: `<agentDir>/bytefly/update.json`, the cwd/package key, the 24 h window in `isFresh`, a validated read that degrades to a miss, and the atomic write. |
|
|
1487
|
+
| `update/format.ts` | `updateMarker`, `updateNotice`, `releaseUrl`, and `updateOutcomeText`: the header's `↑0.12.0`, the multi-package notice, and the one line `/bytefly update` prints. |
|
|
1488
|
+
| `update/register.ts` | The lifecycle: suppression, the cache-first session-start read, the async package-manager call, this package's version lookup, the `PI_OFFLINE` and `tui` gates, the once-per-load announcement, the shutdown generation guard, and the `recheck()` handle `/bytefly update` calls. |
|
|
1356
1489
|
|
|
1357
1490
|
## Testing
|
|
1358
1491
|
|
|
@@ -1375,17 +1508,18 @@ folding across a width sweep from 6 to 120 plus wide characters
|
|
|
1375
1508
|
(`footer/render/layout`), exact
|
|
1376
1509
|
golden output at fixed widths (`footer/render/render`), and the install/skip/
|
|
1377
1510
|
restore/toggle lifecycle plus a config-driven price (`extension`). The turn
|
|
1378
|
-
separator
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1511
|
+
separator is covered by its pure formatting (`separator/format`, including the
|
|
1512
|
+
receipt's width ladder), its register/append/render/disable lifecycle
|
|
1513
|
+
(`separator/register`), and the run stats it records. The picker helpers are
|
|
1514
|
+
covered by the pure helpers (`picker/resources`), the toggle
|
|
1382
1515
|
transforms (`picker/toggle`), discovery with an injected factory
|
|
1383
1516
|
(`picker/discovery`), and the runtime state machine (`picker/runtime`). The
|
|
1384
1517
|
unified screen is covered by its pure model merge (`panel/join`), its text
|
|
1385
1518
|
formatter (`panel/format`), the settings catalogue and its cycling
|
|
1386
1519
|
(`panel/settings`), the scope-aware settings runtime (`panel/settings-runtime`,
|
|
1387
1520
|
including a nested leaf write that keeps its siblings),
|
|
1388
|
-
the screen's rendering
|
|
1521
|
+
the screen's rendering (`panel/tui`), its editing key map (`tui/editing`),
|
|
1522
|
+
the shared frame (`tui/frame`), and the command through
|
|
1389
1523
|
the bytefly factory (`panel/commands`).
|
|
1390
1524
|
The doctor surface is covered by its pure report
|
|
1391
1525
|
formatting (`doctor/format`), its config loader (`doctor/config`), and
|
|
@@ -1394,14 +1528,15 @@ through the factory (`doctor/register`). The notify capability is covered by its
|
|
|
1394
1528
|
(`notify/config`), the pure text builders (`notify/format`), method selection and
|
|
1395
1529
|
delivery over recording seams (`notify/dispatch`), and its four triggers,
|
|
1396
1530
|
reload, and shutdown through `registerNotify` (`notify/register`). The update
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
and
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1531
|
+
surface is covered by the version-ordering table (`update/version`), Pi's package
|
|
1532
|
+
list and the injected registry read (`update/check`), the host shim and its
|
|
1533
|
+
idempotent restore (`update/suppress`), the per-load store (`update/state`), the
|
|
1534
|
+
marker, multi-package notice, release URL, and recheck wording (`update/format`),
|
|
1535
|
+
the project-scoped snapshot and its window (`update/cache`), and its lifecycle —
|
|
1536
|
+
a fresh matching entry reused without a package-manager call, a stale one re-read
|
|
1537
|
+
and rewritten, silent on failure or an empty list, cache-only offline, skipped
|
|
1538
|
+
outside `tui`, an explicit `recheck()` that ignores the window, and immunity to a
|
|
1539
|
+
reply that lands after shutdown (`update/register`).
|
|
1405
1540
|
The user-message nameplate is covered by its pure transform
|
|
1406
1541
|
(`message/format`, including a render through pi-tui's real `Markdown`) and its
|
|
1407
1542
|
registration (`message/register`), plus the factory check in `extension`.
|