@gavin-hu/my-pi-agent 0.8.1 → 0.9.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 +8 -7
- package/README.zh-CN.md +7 -7
- package/assets/file-browse.png +0 -0
- package/assets/plan-review.png +0 -0
- package/extensions/bytefly/README.md +49 -36
- package/extensions/bytefly/doctor/format.ts +36 -10
- package/extensions/bytefly/doctor/tools.ts +6 -5
- package/extensions/bytefly/footer/config.ts +1 -1
- package/extensions/bytefly/footer/render/format.ts +5 -18
- package/extensions/bytefly/footer/render/layout.ts +2 -1
- package/extensions/bytefly/footer/render/segments.ts +51 -78
- package/extensions/bytefly/header/component.ts +33 -16
- package/extensions/bytefly/header/config.ts +28 -18
- package/extensions/bytefly/index.ts +1 -1
- package/extensions/bytefly/panel/commands.ts +69 -35
- package/extensions/bytefly/panel/format.ts +8 -8
- package/extensions/bytefly/panel/tui.ts +45 -70
- package/extensions/bytefly/separator/config.ts +16 -8
- package/extensions/bytefly/separator/format.ts +13 -40
- package/extensions/bytefly/separator/types.ts +0 -10
- package/extensions/document/README.md +1 -1
- package/extensions/document/render.ts +11 -10
- package/extensions/document/tool.ts +1 -1
- package/extensions/file-browse/README.md +51 -9
- package/extensions/file-browse/client.ts +103 -2
- package/extensions/file-browse/config.ts +12 -0
- package/extensions/file-browse/diff.ts +187 -0
- package/extensions/file-browse/git.ts +176 -1
- package/extensions/file-browse/html.ts +385 -19
- package/extensions/file-browse/index.ts +15 -4
- package/extensions/file-browse/markdown.ts +33 -0
- package/extensions/file-browse/router.ts +94 -2
- package/extensions/file-browse/server.ts +4 -1
- package/extensions/goal/format.ts +11 -10
- package/extensions/goal/tools.ts +6 -5
- package/extensions/goal/tui.ts +1 -1
- package/extensions/job/README.md +2 -2
- package/extensions/job/format.ts +36 -13
- package/extensions/job/index.ts +1 -1
- package/extensions/job/tools.ts +11 -10
- package/extensions/job/tui.ts +141 -220
- package/extensions/job/ui.ts +24 -49
- package/extensions/memory/README.md +1 -1
- package/extensions/memory/tools.ts +4 -3
- package/extensions/memory/tui.ts +32 -36
- package/extensions/plan/README.md +64 -34
- package/extensions/plan/blocks.ts +44 -2
- package/extensions/plan/feedback.ts +20 -5
- package/extensions/plan/index.ts +1 -1
- package/extensions/plan/runtime.ts +3 -2
- package/extensions/plan/tools.ts +23 -22
- package/extensions/plan/tui.ts +21 -27
- package/extensions/plan/web-client.ts +335 -30
- package/extensions/plan/web-page.ts +110 -30
- package/extensions/plan/web-router.ts +6 -4
- package/extensions/plan/web.ts +41 -10
- package/extensions/question/README.md +1 -1
- package/extensions/question/tools.ts +12 -11
- package/extensions/question/tui.ts +132 -76
- package/extensions/rewind/README.md +1 -1
- package/extensions/rewind/format.ts +29 -1
- package/extensions/rewind/rewind-tui.ts +66 -62
- package/extensions/rewind/status.ts +3 -2
- package/extensions/subagent/render.ts +62 -47
- package/extensions/todo/README.md +2 -2
- package/extensions/todo/format.ts +31 -10
- package/extensions/todo/tools.ts +5 -4
- package/extensions/todo/tui.ts +45 -26
- package/extensions/watch/README.md +2 -2
- package/extensions/watch/format.ts +33 -13
- package/extensions/watch/index.ts +1 -1
- package/extensions/watch/tools.ts +12 -7
- package/extensions/watch/tui.ts +135 -194
- package/extensions/watch/ui.ts +24 -46
- package/extensions/web-access/fetch/tool.ts +12 -11
- package/extensions/web-access/search/tool.ts +16 -13
- package/extensions/wechat/README.md +2 -2
- package/extensions/wechat/index.ts +4 -3
- package/extensions/wechat/login-screen.ts +8 -5
- package/extensions/wechat/status-screen.ts +41 -22
- package/extensions/wechat/tools.ts +6 -5
- package/extensions/worktree/enter.ts +1 -1
- package/extensions/worktree/index.ts +1 -1
- package/extensions/worktree/runtime.ts +1 -1
- package/lib/README.md +10 -7
- package/lib/requirements.ts +2 -2
- package/lib/{tui.ts → tui/chrome.ts} +9 -30
- package/lib/tui/columns.ts +96 -0
- package/lib/{list-cursor.ts → tui/cursor.ts} +56 -3
- package/lib/tui/gauge.ts +78 -0
- package/lib/tui/index.ts +25 -0
- package/lib/tui/line-pane.ts +173 -0
- package/lib/tui/rows.ts +109 -0
- package/lib/tui/rules.ts +88 -0
- package/lib/tui/status-controller.ts +107 -0
- package/lib/tui/tokens.ts +58 -0
- package/package.json +1 -1
- /package/lib/{ui.ts → tui/glyphs.ts} +0 -0
package/README.md
CHANGED
|
@@ -59,10 +59,11 @@ pi -e . # try it for one run
|
|
|
59
59
|
|
|
60
60
|
Then, from inside Pi:
|
|
61
61
|
|
|
62
|
-
- `/
|
|
63
|
-
runtime health and enables or disables one.
|
|
64
|
-
- `/doctor`
|
|
65
|
-
checks that each enabled extension has what it needs
|
|
62
|
+
- `/bytefly [extension] [refresh]` opens the extension screen, lists every loaded
|
|
63
|
+
extension with its runtime health, and enables or disables one.
|
|
64
|
+
- `/bytefly doctor [extension] [refresh]` prints the doctor report —
|
|
65
|
+
`run_doctor`'s text — and checks that each enabled extension has what it needs
|
|
66
|
+
at runtime.
|
|
66
67
|
- `/settings` → **Theme** selects a theme.
|
|
67
68
|
- `/plan <task>` starts a task in read-only planning mode.
|
|
68
69
|
|
|
@@ -105,7 +106,7 @@ extension's own `README.md` has the full tool and command surface.
|
|
|
105
106
|
|
|
106
107
|
| Extension | Tools and commands | What it does |
|
|
107
108
|
|---|---|---|
|
|
108
|
-
| [`bytefly`](./extensions/bytefly/) | `/bytefly
|
|
109
|
+
| [`bytefly`](./extensions/bytefly/) | `/bytefly` (with the `doctor` subcommand), `run_doctor` | A themed header and width-adaptive footer, a rule between completed turns, the `/bytefly` extension screen that lists every extension with its health and enables or disables one (`/bytefly doctor` prints the doctor report), and an opt-in `notify` capability that raises OS notifications when a run or a background job finishes or the agent asks for input. DeepSeek is priced out of the box, and `bytefly.json` is the shared config document every extension reads. |
|
|
109
110
|
| [`bytefly-dark`](./themes/bytefly-dark.json) / [`bytefly-light`](./themes/bytefly-light.json) | `/settings` → **Theme** | A GitHub-inspired dark palette and its light companion, with optional automatic light/dark switching. |
|
|
110
111
|
|
|
111
112
|
## Configuration
|
|
@@ -146,9 +147,9 @@ stops the factories from registering; to drop the whole package, use Pi's
|
|
|
146
147
|
- **OS** — Windows, macOS, and Linux; the full check suite runs on all three in
|
|
147
148
|
CI.
|
|
148
149
|
- **git** on `PATH` for the `worktree` and `rewind` extensions; everything else
|
|
149
|
-
degrades or disables cleanly, and `/doctor` tells you what is missing.
|
|
150
|
+
degrades or disables cleanly, and `/bytefly doctor` tells you what is missing.
|
|
150
151
|
- Optional runtime pieces (for example a browser for HTML exports) are reported
|
|
151
|
-
per extension by `/doctor`.
|
|
152
|
+
per extension by `/bytefly doctor`.
|
|
152
153
|
|
|
153
154
|
## Contributing
|
|
154
155
|
|
package/README.zh-CN.md
CHANGED
|
@@ -55,10 +55,10 @@ pi -e . # 试运行一次
|
|
|
55
55
|
|
|
56
56
|
然后在 Pi 中:
|
|
57
57
|
|
|
58
|
-
- `/
|
|
59
|
-
|
|
60
|
-
- `/doctor`
|
|
61
|
-
|
|
58
|
+
- `/bytefly [extension] [refresh]` 打开扩展屏幕,列出每个已加载扩展及其运行时健康
|
|
59
|
+
状况,并启用或禁用一个扩展。
|
|
60
|
+
- `/bytefly doctor [extension] [refresh]` 打印 doctor 报告(`run_doctor` 的文本),
|
|
61
|
+
检查每个已启用扩展在运行时是否具备所需条件。
|
|
62
62
|
- `/settings` → **Theme** 选择主题。
|
|
63
63
|
- `/plan <任务>` 以只读规划模式开始一个任务。
|
|
64
64
|
|
|
@@ -101,7 +101,7 @@ pi -e . # 试运行一次
|
|
|
101
101
|
|
|
102
102
|
| 扩展 | 工具与命令 | 说明 |
|
|
103
103
|
|---|---|---|
|
|
104
|
-
| [`bytefly`](./extensions/bytefly/) | `/bytefly
|
|
104
|
+
| [`bytefly`](./extensions/bytefly/) | `/bytefly`(`doctor` 子命令)、`run_doctor` | 主题化头部与宽度自适应页脚、已完成回合之间的分隔线、`/bytefly` 扩展屏幕——列出每个扩展及其健康状况并启用或禁用一个扩展(`/bytefly doctor` 打印 doctor 报告);以及可选的 `notify` 能力:当一次运行或后台任务结束、或智能体请求输入时发出系统通知。DeepSeek 开箱即定价,`bytefly.json` 是每个扩展都会读取的共享配置文档。 |
|
|
105
105
|
| [`bytefly-dark`](./themes/bytefly-dark.json) / [`bytefly-light`](./themes/bytefly-light.json) | `/settings` → **Theme** | GitHub 风格的深色调色板及其浅色搭档,并支持可选的自动浅色/深色切换。 |
|
|
106
106
|
|
|
107
107
|
## 配置
|
|
@@ -139,8 +139,8 @@ Pi 的 `--no-extensions`,或从你的设置中删除该包。
|
|
|
139
139
|
- **Pi** —— 需要一个可用的安装;`my-pi-agent` 是一个包,不是分叉。
|
|
140
140
|
- **操作系统** —— Windows、macOS 和 Linux;完整检查套件在三者的 CI 上都会运行。
|
|
141
141
|
- **git** 需在 `PATH` 上,供 `worktree` 和 `rewind` 扩展使用;其余部分会优雅降级或
|
|
142
|
-
禁用,`/doctor` 会告诉你缺什么。
|
|
143
|
-
- 可选的运行时组件(例如用于 HTML 导出的浏览器)由 `/doctor` 按扩展报告。
|
|
142
|
+
禁用,`/bytefly doctor` 会告诉你缺什么。
|
|
143
|
+
- 可选的运行时组件(例如用于 HTML 导出的浏览器)由 `/bytefly doctor` 按扩展报告。
|
|
144
144
|
|
|
145
145
|
## 参与贡献
|
|
146
146
|
|
package/assets/file-browse.png
CHANGED
|
Binary file
|
package/assets/plan-review.png
CHANGED
|
Binary file
|
|
@@ -23,17 +23,17 @@ The extension owns five surfaces: the startup header, the footer, the rule
|
|
|
23
23
|
between completed turns, the extension screen, and notifications.
|
|
24
24
|
|
|
25
25
|
**Header.** A nameplate: a two-tone half-block mark from the active theme's
|
|
26
|
-
`accent` / `
|
|
27
|
-
chrome identity (`enhanced by bytefly` and the package version), a
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
two-tone `Pi` wordmark.
|
|
26
|
+
`accent` / `warn` roles, the agent identity (`Pi`, bold, and its version), the
|
|
27
|
+
chrome identity (`enhanced by bytefly` and the package version), a signature
|
|
28
|
+
rule whose `accent` lead sits under the mark, and a grouped help block. The help
|
|
29
|
+
keys resolve live from Pi's keybindings, so a rebound key shows the user's
|
|
30
|
+
chord; the identity and help text are `meta` / `faint` so the mark keeps the
|
|
31
|
+
eye. It is installed only in interactive (`tui`) sessions, and on terminals that
|
|
32
|
+
cannot render half blocks the mark falls back to a two-tone `Pi` wordmark.
|
|
33
33
|
|
|
34
34
|
```
|
|
35
35
|
█▀█ Pi v1.2.0
|
|
36
|
-
█▀ █ enhanced by bytefly v0.
|
|
36
|
+
█▀ █ enhanced by bytefly v0.8.1
|
|
37
37
|
─────────────────────────────────────────────────
|
|
38
38
|
escape to interrupt · ctrl+c to clear · ctrl+d to exit (empty)
|
|
39
39
|
ctrl+o to expand tools · ctrl+t to expand thinking · ctrl+l to select model
|
|
@@ -133,19 +133,18 @@ the platform notifier (`osascript`, `notify-send`); see
|
|
|
133
133
|
| Command | What it does |
|
|
134
134
|
|---|---|
|
|
135
135
|
| `/bytefly [extension] [refresh]` | Open the extension screen. In `tui` it mounts a docked list; every other mode prints the grouped listing, or one extension's full findings when named. |
|
|
136
|
-
| `/
|
|
137
|
-
| `/doctor [extension] [refresh]` | Alias for `/bytefly`: the same screen and the same handler. |
|
|
136
|
+
| `/bytefly doctor [extension] [refresh]` | Print the doctor report. Outside `tui` it prints `run_doctor`'s text for every extension, or one named extension's findings; in `tui` it mounts the same docked screen. |
|
|
138
137
|
|
|
139
|
-
Tab completes extension names and `refresh
|
|
138
|
+
Tab completes `doctor`, extension names, and `refresh`.
|
|
140
139
|
|
|
141
140
|
## Behaviour by mode
|
|
142
141
|
|
|
143
142
|
The header, footer, and turn rule are installed only in interactive (`tui`)
|
|
144
143
|
sessions and are always on; every mode loads the extension, and non-TUI modes
|
|
145
144
|
change nothing. The screen is available in every mode: in `tui`, `/bytefly` and
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
145
|
+
`/bytefly doctor` mount the docked screen, while RPC, JSON, and print modes
|
|
146
|
+
print the grouped listing with a per-row health suffix and the headline, or that
|
|
147
|
+
extension's full findings when one is named. The
|
|
149
148
|
proactive session-start warning is skipped when there is no UI. Notify runs in
|
|
150
149
|
every mode and picks its method from the environment; the OSC methods need a
|
|
151
150
|
TTY, so a print/JSON/RPC run gets an OS-level notification or none.
|
|
@@ -394,10 +393,13 @@ it:
|
|
|
394
393
|
extension Pi resolves for the session, so the list matches what actually loads.
|
|
395
394
|
It merges the former extensions picker and doctor report into one row per
|
|
396
395
|
extension: the picker's enable checkbox and label, the doctor's worst-severity
|
|
397
|
-
glyph and summary.
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
396
|
+
glyph and summary. The screen is drawn from the design system: a label-first
|
|
397
|
+
`bytefly ────` title rule, one row grammar (`❯ ◼ ✓ name … summary`), and the
|
|
398
|
+
shared `◼` / `◻` checkbox. `/bytefly doctor [extension] [refresh]` selects the doctor
|
|
399
|
+
report, the same text the `run_doctor` tool returns; in `tui` it opens the same
|
|
400
|
+
screen. `[extension]` narrows either surface to one extension and `refresh`
|
|
401
|
+
re-probes the doctor before it opens. Tab completes `doctor`, extension names,
|
|
402
|
+
and `refresh`.
|
|
401
403
|
|
|
402
404
|
The screen reuses Pi's own settings and package resolution (`SettingsManager`
|
|
403
405
|
plus `DefaultPackageManager` with `onMissing: "skip"`), so opening it never
|
|
@@ -408,7 +410,7 @@ installs or fetches a package.
|
|
|
408
410
|
- Omits `bytefly`'s own entrypoint from the picker groups, so the tool that
|
|
409
411
|
manages the list is never a selectable row; its doctor report still appears in
|
|
410
412
|
the trailing `Not resolved` group.
|
|
411
|
-
- Shows whether each one is enabled (
|
|
413
|
+
- Shows whether each one is enabled (`◼`) or disabled (`◻`).
|
|
412
414
|
- Shows the worst severity for a reported extension (`✓` ok, `!` degraded, `✕`
|
|
413
415
|
missing, `∅` disabled) and its summary; an extension with no doctor report
|
|
414
416
|
leaves the glyph column and the summary blank rather than claiming `ok`.
|
|
@@ -524,6 +526,9 @@ control-free line before it reaches an escape sequence or a shell argument.
|
|
|
524
526
|
|
|
525
527
|
## Limitations
|
|
526
528
|
|
|
529
|
+
- **`doctor` is a reserved first argument.** `/bytefly doctor` always selects the
|
|
530
|
+
report, so an extension literally named `doctor` cannot be narrowed to by
|
|
531
|
+
name.
|
|
527
532
|
- **The picker manages only the `extensions` resource type.** Skills, prompts,
|
|
528
533
|
and themes are handled by Pi's own `pi config`.
|
|
529
534
|
- **Built-in extensions are not listed** (`builtin:mcp`, `builtin:codemode`, …):
|
|
@@ -602,7 +607,7 @@ rather than showing a wrong value.
|
|
|
602
607
|
|---|---|
|
|
603
608
|
| Header | `ctx.ui.setHeader` with a custom component, replacing Pi's built-in header; installed only when `ctx.mode === "tui"`. The mark and text are drawn from the active theme's tokens, the help keys resolve live through `keyText`, and the mark falls back to a wordmark on Apple Terminal (`isAppleTerminalSession`), mirroring Pi's built-in. |
|
|
604
609
|
| Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
|
|
605
|
-
| Screen command | `pi.registerCommand("bytefly"
|
|
610
|
+
| Screen command | `pi.registerCommand("bytefly")` takes `[doctor] [extension] [refresh]`: `tui` mounts a dock screen via `ctx.ui.custom()` with the rails suppressed; other modes print through `ctx.ui.notify()` — the grouped listing, or `run_doctor`'s report for `doctor`. Tab completes `doctor`, extension names, and `refresh`. |
|
|
606
611
|
| Turn separator | `registerEntryRenderer("bytefly-separator")` draws each rule; `agent_settled` appends `pi.appendEntry("bytefly-separator", { turn })` in `tui` mode only. |
|
|
607
612
|
| Notifications | `agent_settled` (skipped when aborted), `ui_prompt_start` only while `agent_start`…`agent_settled` marks a run active, and `my-pi-agent/job-finished` on `pi.events`; the `notify` section of `bytefly.json` gates each. Delivery writes an OSC 777/99 sequence to stdout or spawns `osascript`, `notify-send`, or `powershell.exe`. The bus subscription is created in `session_start` and released in `session_shutdown`, and the `job` extension never imports bytefly. |
|
|
608
613
|
| Picker discovery | `SettingsManager.create(...)` plus `DefaultPackageManager.resolve({ onMissing: "skip" })`, both public exports; both views drop `bytefly`'s own entrypoint. |
|
|
@@ -617,12 +622,18 @@ rather than showing a wrong value.
|
|
|
617
622
|
|
|
618
623
|
## Design notes
|
|
619
624
|
|
|
625
|
+
- **One kit, one look.** Every bytefly surface is drawn from the package's
|
|
626
|
+
`lib/tui/` design system: a role is resolved by the active theme, a rule comes
|
|
627
|
+
from `rules.ts`, a list row from `rows.ts`, a meter from `gauge.ts`, and a
|
|
628
|
+
width from `columns.ts`. Nothing in bytefly names a literal color, and a
|
|
629
|
+
theme swap re-skins the whole chrome.
|
|
620
630
|
- **The header is a nameplate, not a dashboard.** Pi's built-in brand colors are
|
|
621
631
|
fixed, so the mark ignores the active theme; bytefly's header draws a two-tone
|
|
622
|
-
mark from `accent`/`
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
632
|
+
mark from the `accent`/`warn` roles, a signature rule whose accent lead sits
|
|
633
|
+
under the mark, and pairs them with the agent identity, the chrome identity,
|
|
634
|
+
and a grouped help block. It adds no session or model data — that is the
|
|
635
|
+
footer's job — and it stays a fixed four-plus rows so the startup transcript
|
|
636
|
+
never reflows.
|
|
626
637
|
- **Two lines, four zones.** Line 1 is identity (`pwd` left, branch + worktree
|
|
627
638
|
right); line 2 is resources (meters left, model + level right). This keeps
|
|
628
639
|
"where am I / what state" separate from "how much am I burning".
|
|
@@ -722,7 +733,7 @@ rather than showing a wrong value.
|
|
|
722
733
|
reads the same command whether a tool failed or the report named it.
|
|
723
734
|
- **The doctor is quiet by default at startup.** Only `missing` findings warn,
|
|
724
735
|
only for enabled extensions, only with a UI, and only once per session;
|
|
725
|
-
`degraded` findings — including a malformed config — wait in `/doctor`, because
|
|
736
|
+
`degraded` findings — including a malformed config — wait in `/bytefly doctor`, because
|
|
726
737
|
a session that nags about an optional package is worse than one that never
|
|
727
738
|
mentions it.
|
|
728
739
|
- **Probe the real thing.** `subagent`'s requirement resolves through the same
|
|
@@ -737,13 +748,15 @@ rather than showing a wrong value.
|
|
|
737
748
|
The surfaces are folders: `header/`, `footer/` (the status bar and its price
|
|
738
749
|
calculation), `separator/`, `panel/` (the unified screen and its merged model),
|
|
739
750
|
`picker/` (discovery and the settings store), `doctor/` (the `run_doctor` tool
|
|
740
|
-
and its probe runtime), and `notify/`.
|
|
751
|
+
and its probe runtime), and `notify/`. The chrome and the screen are drawn from
|
|
752
|
+
the package's [`lib/tui/`](../../lib/tui/) design system (tokens, rules, rows,
|
|
753
|
+
columns, gauge), so the look follows the active theme.
|
|
741
754
|
|
|
742
755
|
| File | Responsibility |
|
|
743
756
|
|---|---|
|
|
744
757
|
| `index.ts` | Composition root: the disable guard and the six `register*` calls. |
|
|
745
|
-
| `header/config.ts` | Header tuning (`HEADER_CONFIG`): mark and identity
|
|
746
|
-
| `header/component.ts` | `ByteflyHeader`: the mark, identity rows, rule, and grouped help, plus its factory. |
|
|
758
|
+
| `header/config.ts` | Header tuning (`HEADER_CONFIG`): mark and identity roles, padding, tagline, and the grouped help entries. |
|
|
759
|
+
| `header/component.ts` | `ByteflyHeader`: the mark, identity rows, signature rule, and grouped help, plus its factory. |
|
|
747
760
|
| `header/register.ts` | Installs/restores the header and owns its session lifecycle. |
|
|
748
761
|
| `footer/register.ts` | Installs/restores the footer and owns its session lifecycle. |
|
|
749
762
|
| `footer/config.ts` | Bar tuning (`CONFIG`): thresholds, gauge, separators, icons, status keys, labels. |
|
|
@@ -755,22 +768,22 @@ and its probe runtime), and `notify/`.
|
|
|
755
768
|
| `footer/price/rates.ts` | Model-key matching: exact and wildcard, most specific first. |
|
|
756
769
|
| `footer/price/schedule.ts` | Peak-window parsing and evaluation in a configured zone. |
|
|
757
770
|
| `footer/price/price.ts` | Records → totals: rates, peak multiplier, recorded-cost fallback. |
|
|
758
|
-
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd,
|
|
771
|
+
| `footer/render/format.ts` | Generic formatters (tokens, cost in the configured currency, cwd, the context role, truncation). |
|
|
759
772
|
| `footer/render/status.ts` | Status-chip transforms: `compactStatus` and `dropStatusDetail`. |
|
|
760
|
-
| `footer/render/segments.ts` | The segment builders: forms, weights, separators,
|
|
773
|
+
| `footer/render/segments.ts` | The segment builders: forms, weights, separators, roles. |
|
|
761
774
|
| `footer/render/lines.ts` | Snapshot → two `LineSpec`s; status routing. |
|
|
762
775
|
| `footer/render/layout.ts` | Width reduction and right-zone folding. |
|
|
763
776
|
| `footer/render/footer.ts` | `StatusBar` component and footer factory. |
|
|
764
|
-
| `separator/config.ts` | Turn-rule tuning: `customType`, glyph, label prefix, padding, and
|
|
777
|
+
| `separator/config.ts` | Turn-rule tuning: `customType`, glyph, label prefix, padding, and roles. |
|
|
765
778
|
| `separator/register.ts` | Registers the entry renderer and appends a separator on `agent_settled`. |
|
|
766
779
|
| `separator/component.ts` | `SeparatorComponent`: the stateless entry renderer. |
|
|
767
|
-
| `separator/format.ts` | Pure `
|
|
768
|
-
| `separator/types.ts` | `TurnSeparatorData
|
|
780
|
+
| `separator/format.ts` | Pure `separatorLine`: the centered turn rule, drawn by the kit's `centeredRule`. |
|
|
781
|
+
| `separator/types.ts` | `TurnSeparatorData`. |
|
|
769
782
|
| `panel/types.ts` | `PanelRow` and `PanelModel`, the merged row model. |
|
|
770
783
|
| `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering. |
|
|
771
784
|
| `panel/format.ts` | Non-TUI text: the headline and the grouped listing with a per-row health suffix. |
|
|
772
|
-
| `panel/tui.ts` | `PanelComponent`, the unified dock screen. |
|
|
773
|
-
| `panel/commands.ts` | `/bytefly
|
|
785
|
+
| `panel/tui.ts` | `PanelComponent`, the unified dock screen, drawn from the `lib/tui/` kit. |
|
|
786
|
+
| `panel/commands.ts` | `/bytefly`: one command for the screen, the `doctor` report, and their text modes. |
|
|
774
787
|
| `picker/types.ts` | Picker host seams (`SettingsStore`, `ExtensionResolver`, `Discovery`) and row types. |
|
|
775
788
|
| `picker/resources.ts` | Pure grouping, labels, display names, and pattern helpers. |
|
|
776
789
|
| `picker/toggle.ts` | Pure next-settings transforms for global and project toggles. |
|
|
@@ -781,7 +794,7 @@ and its probe runtime), and `notify/`.
|
|
|
781
794
|
| `doctor/tools.ts` | The `run_doctor` tool and its renderers. |
|
|
782
795
|
| `doctor/schema.ts` | Tool parameters and the structured output schema. |
|
|
783
796
|
| `doctor/config.ts` | `DEFAULT_CONFIG`, `normalizeConfig`, `loadConfig` for the `doctor` section of `bytefly.json`. |
|
|
784
|
-
| `doctor/format.ts` | Pure report text, summary, glyphs, detail lines, and the proactive warning sentence. |
|
|
797
|
+
| `doctor/format.ts` | Pure report text, summary, severity roles and glyphs, detail lines, and the proactive warning sentence. |
|
|
785
798
|
| `notify/types.ts` | `NotifyConfig`, `NotifyMethod`, and the method list. |
|
|
786
799
|
| `notify/config.ts` | The `notify` section of `bytefly.json`: defaults, validation, loader. |
|
|
787
800
|
| `notify/dispatch.ts` | Method selection and delivery: OSC 777/99, Windows toast, `osascript`, `notify-send`, over injected seams. |
|
|
@@ -12,7 +12,8 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
|
12
12
|
import { wrapTextWithAnsi } from "@earendil-works/pi-tui";
|
|
13
13
|
import { sanitizeLine } from "../../../lib/format.ts";
|
|
14
14
|
import type { ExtensionReport, Finding, FindingSeverity } from "../../../lib/requirements.ts";
|
|
15
|
-
import { GLYPHS } from "../../../lib/
|
|
15
|
+
import { GLYPHS } from "../../../lib/tui/glyphs.ts";
|
|
16
|
+
import { paint, type TuiRole } from "../../../lib/tui/tokens.ts";
|
|
16
17
|
|
|
17
18
|
/** Counts the report headline uses. */
|
|
18
19
|
export interface ReportCounts {
|
|
@@ -102,15 +103,40 @@ export function formatWarning(findings: readonly Finding[]): string {
|
|
|
102
103
|
byExtension.set(finding.extension, list);
|
|
103
104
|
}
|
|
104
105
|
const parts = [...byExtension].map(([extension, checks]) => `${sanitizeLine(extension)} (${checks.join(", ")})`);
|
|
105
|
-
return `doctor: missing ${parts.join("; ")} — run /doctor`;
|
|
106
|
+
return `doctor: missing ${parts.join("; ")} — run /bytefly doctor`;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
|
-
/** The
|
|
109
|
+
/** The design role a severity is drawn in. */
|
|
110
|
+
export function severityRole(severity: FindingSeverity): TuiRole {
|
|
111
|
+
switch (severity) {
|
|
112
|
+
case "missing":
|
|
113
|
+
return "bad";
|
|
114
|
+
case "degraded":
|
|
115
|
+
return "warn";
|
|
116
|
+
case "info":
|
|
117
|
+
return "faint";
|
|
118
|
+
default:
|
|
119
|
+
return "ok";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** The bare severity glyph, from the shared vocabulary. */
|
|
124
|
+
export function severityGlyphChar(severity: FindingSeverity): string {
|
|
125
|
+
switch (severity) {
|
|
126
|
+
case "missing":
|
|
127
|
+
return GLYPHS.cross;
|
|
128
|
+
case "degraded":
|
|
129
|
+
return GLYPHS.warn;
|
|
130
|
+
case "info":
|
|
131
|
+
return GLYPHS.disabled;
|
|
132
|
+
default:
|
|
133
|
+
return GLYPHS.check;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** The severity glyph, themed by role. */
|
|
109
138
|
export function severityGlyph(severity: FindingSeverity, theme: Theme): string {
|
|
110
|
-
|
|
111
|
-
if (severity === "degraded") return theme.fg("warning", GLYPHS.warn);
|
|
112
|
-
if (severity === "info") return theme.fg("dim", GLYPHS.disabled);
|
|
113
|
-
return theme.fg("success", GLYPHS.check);
|
|
139
|
+
return paint(theme, severityRole(severity), severityGlyphChar(severity));
|
|
114
140
|
}
|
|
115
141
|
|
|
116
142
|
/** The severity that represents an extension: worst finding wins. */
|
|
@@ -147,7 +173,7 @@ export function detailLines(
|
|
|
147
173
|
const budget = Math.max(1, rows);
|
|
148
174
|
const shown = includeInfo ? report.findings : report.findings.filter((finding) => finding.severity !== "info");
|
|
149
175
|
if (shown.length === 0) {
|
|
150
|
-
return [` ${theme
|
|
176
|
+
return [` ${paint(theme, "faint", report.enabled ? "no problems" : "disabled")}`];
|
|
151
177
|
}
|
|
152
178
|
|
|
153
179
|
const lines: string[] = [];
|
|
@@ -160,10 +186,10 @@ export function detailLines(
|
|
|
160
186
|
}
|
|
161
187
|
if (finding.hint) {
|
|
162
188
|
for (const line of wrapTextWithAnsi(`→ ${sanitizeLine(finding.hint)}`, Math.max(1, width - 4))) {
|
|
163
|
-
lines.push(` ${theme
|
|
189
|
+
lines.push(` ${paint(theme, "faint", line)}`);
|
|
164
190
|
}
|
|
165
191
|
}
|
|
166
192
|
}
|
|
167
193
|
if (lines.length <= budget) return lines;
|
|
168
|
-
return [...lines.slice(0, budget - 1), ` ${theme
|
|
194
|
+
return [...lines.slice(0, budget - 1), ` ${paint(theme, "faint", "…")}`];
|
|
169
195
|
}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import { missingFindings } from "../../../lib/requirements.ts";
|
|
12
|
-
import { reuseText, toolDetails } from "../../../lib/tui.ts";
|
|
12
|
+
import { reuseText, toolDetails } from "../../../lib/tui/chrome.ts";
|
|
13
|
+
import { paint, type TuiRole } from "../../../lib/tui/tokens.ts";
|
|
13
14
|
import { formatExtension, formatReport, isProblemSeverity } from "./format.ts";
|
|
14
15
|
import type { DoctorRuntime } from "./runtime.ts";
|
|
15
16
|
import { DoctorOutput, DoctorParams, TOOL_NAME, type DoctorArgs, type DoctorStructured } from "./schema.ts";
|
|
@@ -93,20 +94,20 @@ export function registerTools(pi: ExtensionAPI, runtime: DoctorRuntime): void {
|
|
|
93
94
|
const input = args as DoctorArgs;
|
|
94
95
|
const scope = `${input.extension ? ` ${input.extension}` : ""}${input.refresh ? " (refresh)" : ""}`;
|
|
95
96
|
const text = reuseText(context?.lastComponent);
|
|
96
|
-
text.setText(`${theme.fg("toolTitle", "doctor")}${theme
|
|
97
|
+
text.setText(`${theme.fg("toolTitle", "doctor")}${paint(theme, "faint", scope)}`);
|
|
97
98
|
return text;
|
|
98
99
|
},
|
|
99
100
|
|
|
100
101
|
renderResult(result, _options, theme, context) {
|
|
101
102
|
const structured = toolDetails<DoctorStructured>(result.details);
|
|
102
|
-
const tone = (structured?.missing ?? 0) > 0 ? "
|
|
103
|
+
const tone: TuiRole = (structured?.missing ?? 0) > 0 ? "bad" : (structured?.degraded ?? 0) > 0 ? "warn" : "ok";
|
|
103
104
|
const text = reuseText(context?.lastComponent);
|
|
104
105
|
if (!structured) {
|
|
105
106
|
const first = result.content[0];
|
|
106
|
-
text.setText(first?.type === "text" ? first.text : theme
|
|
107
|
+
text.setText(first?.type === "text" ? first.text : paint(theme, "meta", "doctor: no result"));
|
|
107
108
|
return text;
|
|
108
109
|
}
|
|
109
|
-
text.setText(theme
|
|
110
|
+
text.setText(paint(theme, tone, summaryLines(structured).join("\n")));
|
|
110
111
|
return text;
|
|
111
112
|
},
|
|
112
113
|
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* configuration is `bytefly.json`, read by `../price/config.ts`.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { GLYPHS, SEPARATORS, STATUS_KEYS } from "../../../lib/
|
|
10
|
+
import { GLYPHS, SEPARATORS, STATUS_KEYS } from "../../../lib/tui/glyphs.ts";
|
|
11
11
|
|
|
12
12
|
export const CONFIG = {
|
|
13
13
|
/** Context percentage thresholds. */
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
9
|
-
import type { ThemeColor } from "@earendil-works/pi-coding-agent";
|
|
10
9
|
import { stripTerminalSequences, truncateToWidth } from "@earendil-works/pi-tui";
|
|
11
10
|
import { shortenPath } from "../../../../lib/format.ts";
|
|
11
|
+
import { gaugeRole } from "../../../../lib/tui/gauge.ts";
|
|
12
|
+
import type { TuiRole } from "../../../../lib/tui/tokens.ts";
|
|
12
13
|
import { CONFIG } from "../config.ts";
|
|
13
14
|
import { DEFAULT_CURRENCY } from "../price/config.ts";
|
|
14
15
|
import type { Currency } from "../price/types.ts";
|
|
@@ -65,23 +66,9 @@ export function formatCwd(cwd: string, home: string | undefined, level: 0 | 1 |
|
|
|
65
66
|
return parts.length <= 2 ? shortened : `…/${parts.slice(-2).join("/")}`;
|
|
66
67
|
}
|
|
67
68
|
|
|
68
|
-
/**
|
|
69
|
-
export function
|
|
70
|
-
|
|
71
|
-
if (percent === null) return { filled: 0, empty: blocks };
|
|
72
|
-
const clamped = Math.max(0, Math.min(100, percent));
|
|
73
|
-
// Floor so the bar is only full at 100%; force one block for any non-zero
|
|
74
|
-
// usage so a small percentage is still visible.
|
|
75
|
-
const filled = Math.max(clamped > 0 ? 1 : 0, Math.floor((clamped / 100) * blocks));
|
|
76
|
-
return { filled, empty: blocks - filled };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Gauge color for a context percentage. Neutral until it crosses a threshold. */
|
|
80
|
-
export function contextColor(percent: number | null): ThemeColor {
|
|
81
|
-
if (percent === null) return "muted";
|
|
82
|
-
if (percent > CONFIG.thresholds.danger) return "error";
|
|
83
|
-
if (percent > CONFIG.thresholds.warn) return "warning";
|
|
84
|
-
return "muted";
|
|
69
|
+
/** The design role a context percentage is drawn in. Neutral until it crosses a threshold. */
|
|
70
|
+
export function contextRole(percent: number | null): TuiRole {
|
|
71
|
+
return gaugeRole(percent, CONFIG.thresholds);
|
|
85
72
|
}
|
|
86
73
|
|
|
87
74
|
const THINKING_TOKENS: Record<ThinkingLevel, ThinkingColor> = {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
12
12
|
import { truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
13
|
+
import { paint } from "../../../../lib/tui/tokens.ts";
|
|
13
14
|
import { CONFIG } from "../config.ts";
|
|
14
15
|
import type { LineSpec, Segment } from "../types.ts";
|
|
15
16
|
|
|
@@ -135,5 +136,5 @@ export function renderLine(spec: LineSpec, width: number, theme: Theme): string
|
|
|
135
136
|
if (!collapseSeparator(states)) break;
|
|
136
137
|
}
|
|
137
138
|
|
|
138
|
-
return truncateToWidth(assemble(states, target), target, theme
|
|
139
|
+
return truncateToWidth(assemble(states, target), target, paint(theme, "faint", "…"));
|
|
139
140
|
}
|