pi-focus-mode 0.1.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/LICENSE +19 -0
- package/README.md +203 -0
- package/focus-mode.js +2097 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ezoushen
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE.
|
package/README.md
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
# pi-focus-mode
|
|
2
|
+
|
|
3
|
+
Show timing, token, cache, cost, and tool-use statistics for each Pi exchange.
|
|
4
|
+
Each run of thinking and tool calls between pieces of assistant text starts folded
|
|
5
|
+
as one process line, even when it spans assistant messages or turns. The line shows
|
|
6
|
+
thinking and tool counts as `◈ n` and `⚙ m`, plus total wall time, or the current
|
|
7
|
+
block and its live time while streaming. In the running exchange, a tool call that
|
|
8
|
+
has streamed but not yet started shows as `⚙ <tool> queued`. A call whose exchange
|
|
9
|
+
settled, or was restored, without a result shows `no result` in its title and no
|
|
10
|
+
live activity. At the next fold level, each block has a one-line title in stream order, with dim `├` and `└` guides under its process line and `│` continuing through rows with later siblings.
|
|
11
|
+
While an exchange streams, assistant text stays visible. After it settles, an
|
|
12
|
+
exchange with a process and a trailing answer folds its processes and earlier
|
|
13
|
+
assistant text into one dim progress line at the first progress item. Opening that
|
|
14
|
+
line shows the process lines and earlier text beneath it, grouped by dim tree guides;
|
|
15
|
+
the trailing answer stays visible without a guide. Its `1 note` or `N notes` segment
|
|
16
|
+
counts interim text items and is omitted when there are none. An exchange without a
|
|
17
|
+
process or a trailing answer keeps its existing rows.
|
|
18
|
+
Tool titles show the argument, status, duration, and result line count. Thinking
|
|
19
|
+
titles show the trace's last complete sentence, or `Thinking` until one completes.
|
|
20
|
+
With `summaryModel` configured, a short model headline takes its place when ready;
|
|
21
|
+
the leading `≈` marks it as a summary. A failed or timed-out request returns to
|
|
22
|
+
the sentence fallback, on screen and in the saved entry, even after an earlier
|
|
23
|
+
model headline; it gives one warning per session.
|
|
24
|
+
The headline is shortened first to make room for duration and stats.
|
|
25
|
+
Titles also show elapsed time, thinking tokens and rate while streaming; a `~` marks
|
|
26
|
+
token estimates when the provider has not reported reasoning usage. Settled titles
|
|
27
|
+
show duration and word count. Opening a block keeps its title and shows Pi's native
|
|
28
|
+
output below it, two columns beneath its tree guide; a thinking block shows Pi's full trace
|
|
29
|
+
there, regardless of Pi's hide-thinking setting. Process lines, settled progress lines,
|
|
30
|
+
and block titles use the active Pi theme's dim color and italic style, except the line
|
|
31
|
+
selected by the transcript cursor, which uses the theme's accent color and stays
|
|
32
|
+
italic. Picker text and exchange card rows use the same dim italic style; the picker
|
|
33
|
+
border stays upright. Visible assistant text and opened native content keep Pi's own
|
|
34
|
+
styling.
|
|
35
|
+
|
|
36
|
+
Press `ctrl+alt+f` to toggle the latest process between its line and block titles.
|
|
37
|
+
Press `ctrl+alt+e` to toggle the latest exchange's progress line after it settles;
|
|
38
|
+
while it streams, the shortcut opens or folds all its processes. Press
|
|
39
|
+
`ctrl+alt+s` to open the picker; use Up/Down and Enter to toggle an exchange,
|
|
40
|
+
process, or block, and Escape to close it. The exchange row toggles settled progress
|
|
41
|
+
or the streaming processes. The picker marks open items; opening a block also opens
|
|
42
|
+
its process, while folding that block leaves the process open. These controls change
|
|
43
|
+
only the display. In fullscreen mode, left click a process line, progress line, or
|
|
44
|
+
block title to toggle it. Option+left-click a progress or process line toggles that
|
|
45
|
+
row and its direct children; on a block title it behaves like a plain click. A terminal
|
|
46
|
+
that swallows Option+click, for example to move the cursor, sends a plain click.
|
|
47
|
+
Hovering one of these rows brightens its text and puts it
|
|
48
|
+
on the theme's selection background, from the title after its tree guide to the right edge;
|
|
49
|
+
opened native output is not highlighted. The highlight follows the pointer across fold rows,
|
|
50
|
+
assistant text and the exchange card; it can stay on a row after the pointer
|
|
51
|
+
moves straight to Pi's own rows (a user message, the editor), until the pointer
|
|
52
|
+
next crosses the transcript. Terminal multiplexers that Pi runs in button-motion
|
|
53
|
+
mode (tmux, screen, zellij) send no hover events, so there is no highlight there.
|
|
54
|
+
|
|
55
|
+
An experimental transcript cursor is available with `cursorMode: true`. Press
|
|
56
|
+
`ctrl+alt+g` to enter it, Up/Down to move through progress and process lines and the
|
|
57
|
+
block titles of open processes, Enter to toggle the highlighted item, and Escape to
|
|
58
|
+
return to the editor. The selected title also appears in the status line, since
|
|
59
|
+
regular terminal scrollback can leave the highlighted line above the viewport.
|
|
60
|
+
Fullscreen Pi exposes scrolling by line, but its extension UI does not expose the
|
|
61
|
+
selected transcript row's position; the cursor therefore cannot scroll to it.
|
|
62
|
+
|
|
63
|
+
An **exchange** is one uninterrupted work span from a submitted prompt until Pi has
|
|
64
|
+
nothing left to do automatically. A **turn** is one model response plus the tools it
|
|
65
|
+
invokes, so an exchange can contain several turns. The status line shows the current
|
|
66
|
+
or most recent exchange. Exchange and session cards are summary-only and show one
|
|
67
|
+
line when their content fits; at narrower widths Pi wraps the text without
|
|
68
|
+
truncating its numbers. The exchange line contains its duration, finish time when
|
|
69
|
+
the record has `endedAt`, and model, separated by `·`; its metrics follow the model
|
|
70
|
+
in parentheses after one space, separated by `·`. It does not include an exchange
|
|
71
|
+
number. The finish time uses the runtime default locale and local time zone in
|
|
72
|
+
24-hour `HH:MM:SS` style, with the date when that local date is not today. Records
|
|
73
|
+
saved by version 0.1.0 without `endedAt` omit the finish time. The session line keeps
|
|
74
|
+
its turn and exchange counts and follows the same model and metrics layout. Metrics
|
|
75
|
+
show input and output tokens, cache reads as `cache R` with `/ W written` when cache writes are
|
|
76
|
+
nonzero (or `cache W written` when there are writes but no reads), waiting time only
|
|
77
|
+
when nonzero, and total cost at the end even when it is `$0`. Cards omit turns,
|
|
78
|
+
prompts, tools, thinking, and total-token details. Block titles carry individual
|
|
79
|
+
timing and count details.
|
|
80
|
+
|
|
81
|
+
Tool time is the union of tool spans, not their sum, so parallel calls are not counted
|
|
82
|
+
twice. Model time is estimated as turn wall time minus tool time. Output throughput is
|
|
83
|
+
calculated per turn, while cumulative cost and token fields use Pi's reported usage.
|
|
84
|
+
Run `/exstats` to append a cumulative session card. Exchange entries retain block
|
|
85
|
+
durations, status, counts, and headlines outside model context. A model headline
|
|
86
|
+
that arrives after its exchange settles is saved in a separate, unrendered
|
|
87
|
+
`exchange-stats-headline` entry holding only the block id, headline and source, and
|
|
88
|
+
restore applies the latest one. On resume, reload,
|
|
89
|
+
or a branch switch, the extension rebuilds fold state from the active session
|
|
90
|
+
branch without sending historical thinking to the headline model. Older entries
|
|
91
|
+
without block statistics still show their card; their thinking titles use `—` for
|
|
92
|
+
unknown duration.
|
|
93
|
+
|
|
94
|
+
## External contract
|
|
95
|
+
|
|
96
|
+
Pi must emit its documented session, agent, turn, tool, and UI-prompt lifecycle events.
|
|
97
|
+
Display wrappers are installed at `session_start` and released at `session_shutdown`;
|
|
98
|
+
loading the extension without a session leaves Pi's component prototypes unchanged.
|
|
99
|
+
Overlapping extension instances share the wrappers until the last session releases them.
|
|
100
|
+
A tool row renders with the session that received its tool call id. An assistant
|
|
101
|
+
message renders with the session that received a message with its timestamp; when
|
|
102
|
+
several sessions did, with the one whose received thinking or tool calls match the
|
|
103
|
+
message. Sessions whose messages share a timestamp and identical content, or a
|
|
104
|
+
component built before any session received its message, use the latest session.
|
|
105
|
+
Tool folding uses Pi's `ToolExecutionComponent.render` interface from version 0.87.1.
|
|
106
|
+
Thinking folding uses `AssistantMessageComponent.updateContent` and Pi's
|
|
107
|
+
`message_update` events. Its clock starts at the first thinking delta and stops
|
|
108
|
+
at `thinking_end`, the first following non-thinking event, or message end,
|
|
109
|
+
whichever comes first. Streamed snapshots of one assistant message must retain
|
|
110
|
+
the same Pi message timestamp for the local clock to follow them.
|
|
111
|
+
Assistant messages should include usage and cost fields when the provider supports
|
|
112
|
+
them. Model headlines use Pi's configured provider; no separate endpoint is needed.
|
|
113
|
+
|
|
114
|
+
## If the contract is unmet
|
|
115
|
+
|
|
116
|
+
Missing usage fields are reported as zero for exchange totals; the extension does
|
|
117
|
+
not invent exchange token or cost data. Thinking estimates are explicitly marked
|
|
118
|
+
with `~`.
|
|
119
|
+
Missing lifecycle events produce an incomplete or absent span. When UI status is
|
|
120
|
+
unavailable, status updates are skipped. If custom-entry persistence is unavailable,
|
|
121
|
+
the live status can still update and the agent turn continues. If Pi no longer
|
|
122
|
+
provides the tool render interface, a single warning is shown and tool rows use
|
|
123
|
+
Pi's native renderer; exchange stats continue.
|
|
124
|
+
If Pi no longer provides the assistant content interface, a single warning is
|
|
125
|
+
shown and thinking uses Pi's native rendering.
|
|
126
|
+
|
|
127
|
+
The timings are measured locally, then saved in exchange entries. They do not
|
|
128
|
+
claim provider-side queue time, exclusive model compute time, or billing beyond
|
|
129
|
+
the usage object Pi received.
|
|
130
|
+
|
|
131
|
+
## Compatibility
|
|
132
|
+
|
|
133
|
+
Uninstall `pi-exchange-stats` before installing `pi-focus-mode`; both packages
|
|
134
|
+
must not be loaded together. The published `pi-exchange-stats@0.1.0` had no
|
|
135
|
+
settings or environment variables, so no settings migration is needed. Existing
|
|
136
|
+
sessions remain readable through their `exchange-stats` and
|
|
137
|
+
`exchange-stats-headline` entries. The `/exstats` command and `exchange` status
|
|
138
|
+
key stay unchanged.
|
|
139
|
+
|
|
140
|
+
## Settings
|
|
141
|
+
|
|
142
|
+
The optional `focus-mode.json` file in Pi's agent directory configures
|
|
143
|
+
`processKey`, `exchangeKey`, and `pickerKey`. Their defaults are `ctrl+alt+f`,
|
|
144
|
+
`ctrl+alt+e`, and `ctrl+alt+s`. The experimental `cursorKey` defaults to
|
|
145
|
+
`ctrl+alt+g`. Each key value must be a modified Pi key such as
|
|
146
|
+
`ctrl+alt+x` or `alt+enter`; an invalid value uses its default and produces one warning.
|
|
147
|
+
The matching environment variables are `PI_FOCUS_MODE_PROCESS_KEY`,
|
|
148
|
+
`PI_FOCUS_MODE_EXCHANGE_KEY`, `PI_FOCUS_MODE_PICKER_KEY`, and
|
|
149
|
+
`PI_FOCUS_MODE_CURSOR_KEY`. Set `cursorMode` to the boolean `true` in the same
|
|
150
|
+
file, or set `PI_FOCUS_MODE_CURSOR_MODE=true`, to register the cursor shortcut.
|
|
151
|
+
It is off by default. A project's `.pi/focus-mode.json` is not read for the keys
|
|
152
|
+
or `cursorMode`, even in a trusted project.
|
|
153
|
+
|
|
154
|
+
Set `summaryModel` to a `provider/modelId` registered in Pi's model registry.
|
|
155
|
+
It is off by default. Put it in `<agentDir>/focus-mode.json`, or in a trusted
|
|
156
|
+
project's `.pi/focus-mode.json`. For example:
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{ "summaryModel": "my-provider/my-headline-model" }
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`PI_FOCUS_MODE_SUMMARY_MODEL` overrides the file setting. While thinking
|
|
163
|
+
streams, the extension sends at most the last 1,500 trace characters after about
|
|
164
|
+
400 new tokens or six seconds, and once more when the block ends. Requests use
|
|
165
|
+
reasoning off and a 32 token output cap. The model call never delays the turn or
|
|
166
|
+
the trace; with the setting absent or an unknown model, titles use the trace
|
|
167
|
+
sentence.
|
|
168
|
+
|
|
169
|
+
The summary model must honor Pi's reasoning `off` level. Set
|
|
170
|
+
`thinkingLevelMap.off` in that model's Pi `models.json` entry to the provider's
|
|
171
|
+
own value for disabling thinking. For a provider that uses `none`, for example:
|
|
172
|
+
|
|
173
|
+
```json
|
|
174
|
+
{ "thinkingLevelMap": { "off": "none" } }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Without it, a model may spend the 32 token cap reasoning and return no headline.
|
|
178
|
+
|
|
179
|
+
For a development install, do not load this package from a path whose
|
|
180
|
+
`node_modules` contains its own `@earendil-works/pi-*` packages. That path makes
|
|
181
|
+
the display patch land on those private component classes rather than the classes
|
|
182
|
+
used by the running Pi. Stage the built package files outside such a tree, or
|
|
183
|
+
`npm pack` this package and install the tarball with
|
|
184
|
+
`pi install npm:pi-focus-mode@file:/absolute/path/to/pi-focus-mode-0.1.0.tgz`.
|
|
185
|
+
|
|
186
|
+
## Install and verify
|
|
187
|
+
|
|
188
|
+
```sh
|
|
189
|
+
pi install npm:pi-focus-mode
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Submit a prompt that makes at least one tool call and produces thinking. While it
|
|
193
|
+
streams, check that process lines update and assistant text remains visible. After Pi
|
|
194
|
+
settles, check that one progress line covers the work before the final answer; open it
|
|
195
|
+
to see process lines and interim text grouped beneath it with tree guides, while the
|
|
196
|
+
final answer stays unmarked. Check that exchanges without a process or a trailing
|
|
197
|
+
answer stay unfolded. Check that the exchange card uses one line when it fits and
|
|
198
|
+
wraps without truncating numbers at narrower widths, with metrics in parentheses,
|
|
199
|
+
cost last and no expanded detail. Open a process to see individual block timings
|
|
200
|
+
and counts. Run `/exstats` and confirm the session card keeps its turn and exchange
|
|
201
|
+
counts, with metrics in parentheses and following the same metrics rules. To check
|
|
202
|
+
parallel-tool accounting, run two overlapping tools and confirm their union is not
|
|
203
|
+
larger than the exchange wall time.
|