@gavin-hu/my-pi-agent 0.15.0 → 0.16.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 +12 -11
- package/README.zh-CN.md +9 -7
- package/extensions/bytefly/README.md +98 -116
- package/extensions/bytefly/notice/component.ts +6 -4
- package/extensions/bytefly/notice/config.ts +16 -2
- package/extensions/bytefly/panel/format.ts +3 -8
- package/extensions/bytefly/panel/join.ts +1 -6
- package/extensions/bytefly/panel/settings.ts +74 -377
- package/extensions/bytefly/panel/tui/entries.ts +16 -14
- package/extensions/bytefly/panel/tui/extensions-view.ts +3 -0
- package/extensions/bytefly/panel/tui/frame.ts +2 -2
- package/extensions/bytefly/panel/tui/settings-view.ts +8 -12
- package/extensions/bytefly/panel/tui.ts +4 -6
- package/extensions/bytefly/picker/resources.ts +7 -3
- package/extensions/bytefly/working/register.ts +2 -8
- package/extensions/check/tools.ts +2 -11
- package/extensions/context/README.md +162 -0
- package/extensions/context/collect.ts +53 -0
- package/extensions/context/commands.ts +100 -0
- package/extensions/context/format.ts +82 -0
- package/extensions/context/index.ts +16 -0
- package/extensions/context/report.ts +319 -0
- package/extensions/context/tui.ts +268 -0
- package/extensions/context/types.ts +122 -0
- package/extensions/file-browse/README.md +83 -8
- package/extensions/file-browse/client.ts +3 -1
- package/extensions/file-browse/config.ts +23 -0
- package/extensions/file-browse/files.ts +183 -48
- package/extensions/file-browse/fuzzy.ts +65 -11
- package/extensions/file-browse/html.ts +78 -133
- package/extensions/file-browse/index.ts +17 -2
- package/extensions/file-browse/live-client.ts +158 -0
- package/extensions/file-browse/live.ts +256 -0
- package/extensions/file-browse/markdown.ts +3 -10
- package/extensions/file-browse/raw-html.ts +3 -10
- package/extensions/file-browse/router.ts +33 -8
- package/extensions/file-browse/server.ts +78 -13
- package/extensions/file-browse/styles.ts +124 -0
- package/extensions/file-open/README.md +1 -2
- package/extensions/{document → file-read}/README.md +72 -56
- package/extensions/{document → file-read}/config.ts +12 -9
- package/extensions/{document → file-read}/extract/doc.ts +2 -2
- package/extensions/{document → file-read}/extract/docx.ts +3 -3
- package/extensions/{document → file-read}/extract/file.ts +9 -9
- package/extensions/{document → file-read}/extract/odt.ts +3 -3
- package/extensions/{document → file-read}/extract/pdf.ts +3 -3
- package/extensions/{document → file-read}/extract/rtf.ts +3 -3
- package/extensions/{document → file-read}/extract/xlsx.ts +4 -4
- package/extensions/{document → file-read}/formats.ts +11 -11
- package/extensions/file-read/index.ts +17 -0
- package/extensions/{document → file-read}/paging.ts +15 -13
- package/extensions/{document → file-read}/render.ts +17 -13
- package/extensions/{document → file-read}/schema.ts +7 -7
- package/extensions/{document → file-read}/tool.ts +36 -28
- package/extensions/goal/tools.ts +10 -14
- package/extensions/job/commands.ts +32 -46
- package/extensions/job/runtime.ts +6 -8
- package/extensions/job/tools.ts +7 -26
- package/extensions/memory/commands.ts +30 -44
- package/extensions/memory/tools.ts +6 -14
- package/extensions/plan/tools/enter.ts +6 -7
- package/extensions/plan/tools/exit.ts +6 -7
- package/extensions/plan/tools/steps.ts +6 -7
- package/extensions/plan/tools/write.ts +8 -9
- package/extensions/plan/web-router.ts +2 -12
- package/extensions/plan/web.ts +30 -15
- package/extensions/question/tools.ts +5 -4
- package/extensions/rewind/checklist.ts +10 -3
- package/extensions/rewind/git.ts +27 -14
- package/extensions/rewind/hunk-picker.ts +1 -1
- package/extensions/rewind/path-picker.ts +1 -1
- package/extensions/rewind/review-tui.ts +3 -3
- package/extensions/rewind/snapshot.ts +13 -4
- package/extensions/subagent/background-tui.ts +1 -1
- package/extensions/subagent/background.ts +1 -7
- package/extensions/todo/tools.ts +10 -14
- package/extensions/watch/README.md +5 -5
- package/extensions/watch/commands.ts +33 -47
- package/extensions/watch/runtime.ts +5 -7
- package/extensions/watch/tools.ts +7 -18
- package/extensions/web-access/README.md +3 -3
- package/extensions/web-access/search/search.ts +9 -18
- package/extensions/wechat/timer.ts +9 -30
- package/extensions/wechat/tools.ts +4 -7
- package/extensions/worktree/status.ts +14 -9
- package/lib/README.md +12 -8
- package/lib/escape.ts +15 -2
- package/lib/git/read.ts +20 -0
- package/lib/http/headers.ts +20 -0
- package/lib/http/server.ts +22 -4
- package/lib/pdf.ts +2 -2
- package/lib/pool.ts +62 -0
- package/lib/requirements.ts +2 -2
- package/lib/screen-session.ts +85 -0
- package/lib/timer.ts +61 -0
- package/lib/tui/README.md +3 -3
- package/lib/tui/columns.ts +33 -8
- package/lib/tui/dock-screen.ts +12 -4
- package/lib/tui/rows.ts +15 -6
- package/lib/tui/rules.ts +4 -8
- package/lib/tui/tool.ts +55 -2
- package/package.json +8 -4
- package/skills/changelog/SKILL.md +136 -0
- package/extensions/document/index.ts +0 -17
- /package/extensions/{document → file-read}/deadline.ts +0 -0
- /package/extensions/{document → file-read}/extract/vendor.d.ts +0 -0
package/README.md
CHANGED
|
@@ -43,8 +43,8 @@ want the agent to *think first and work safely*:
|
|
|
43
43
|
- **Remember across sessions.** Durable notes live in plain markdown that you
|
|
44
44
|
can read, edit, and version.
|
|
45
45
|
- **Reach the web and your files.** Search, fetch, browse, open, and read
|
|
46
|
-
documents from inside the session, and answer a WeChat chat
|
|
47
|
-
the live session.
|
|
46
|
+
documents and spreadsheets from inside the session, and answer a WeChat chat
|
|
47
|
+
through a bridge to the live session.
|
|
48
48
|
|
|
49
49
|
Everything is optional and independently toggleable. Nothing is forked, and no
|
|
50
50
|
installed Pi file is modified: Pi discovers the resources through the `pi`
|
|
@@ -73,10 +73,10 @@ Then, from inside Pi:
|
|
|
73
73
|
- `/bytefly [extension] [refresh]` opens the control center on Extensions, lists
|
|
74
74
|
every loaded extension with its runtime health, enables or disables one, and
|
|
75
75
|
clears a project override with `x`.
|
|
76
|
-
- `/bytefly settings` opens the control center's Settings section:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
- `/bytefly settings` opens the control center's Settings section: one flat list
|
|
77
|
+
of the fourteen preferences a session changes, each with its value beside the
|
|
78
|
+
label, `Space`/`Enter` to change one and `Tab` for Global/Project scope. Every
|
|
79
|
+
other key is a `bytefly.json` edit, listed in the configuration reference.
|
|
80
80
|
- `/bytefly doctor [extension] [refresh]` prints the doctor report —
|
|
81
81
|
`run_doctor`'s text — and checks that each enabled extension has what it needs
|
|
82
82
|
at runtime.
|
|
@@ -94,9 +94,8 @@ Nothing about the session is sent, and `PI_OFFLINE` skips the check;
|
|
|
94
94
|
|
|
95
95
|
## What you get
|
|
96
96
|
|
|
97
|
-
|
|
98
|
-
do
|
|
99
|
-
command surface.
|
|
97
|
+
18 extensions, 3 packaged skills, and 2 themes, grouped by what you are trying
|
|
98
|
+
to do. Each extension's own `README.md` has the full tool and command surface.
|
|
100
99
|
|
|
101
100
|
### Plan and delegate
|
|
102
101
|
|
|
@@ -110,6 +109,7 @@ command surface.
|
|
|
110
109
|
| [`question`](./extensions/question/) | `ask_user_question` | Ask you one or more structured questions (labelled options plus free-form "Other") and wait. |
|
|
111
110
|
| [`job`](./extensions/job/) | `job`, `/jobs` | Run long-lived shell commands in the background; inspect logs, wait, or kill them. |
|
|
112
111
|
| [`watch`](./extensions/watch/) | `watch`, `/watch` | Tail a file or command output, match lines against patterns, and alert you or hand matching lines to the agent. |
|
|
112
|
+
| [`context`](./extensions/context/) | `/context` | Show where the context window goes — system prompt, tool definitions, conversation by role, injected notes — and compact from the report with the before and after numbers. |
|
|
113
113
|
|
|
114
114
|
### Keep your work safe
|
|
115
115
|
|
|
@@ -124,8 +124,8 @@ command surface.
|
|
|
124
124
|
| Extension | Tools and commands | What it does |
|
|
125
125
|
|---|---|---|
|
|
126
126
|
| [`web-access`](./extensions/web-access/) | `web_search`, `web_fetch` | Search the web (keyless DuckDuckGo by default, optional SearXNG or Brave) and fetch a page as readable text, with paging, `find`, per-hop SSRF checks, and optional PDF support. |
|
|
127
|
-
| [`file-browse`](./extensions/file-browse/) | `/browse` | Start a loopback, read-only file browser rooted at the working directory, with Markdown preview
|
|
128
|
-
| [`
|
|
127
|
+
| [`file-browse`](./extensions/file-browse/) | `/browse` | Start a loopback, read-only file browser rooted at the working directory, with Markdown preview, a fuzzy quick-open palette, and live status for a page left open. |
|
|
128
|
+
| [`file-read`](./extensions/file-read/) | `read_doc` | Extract text from a local PDF, DOCX, DOC, ODT, RTF, or XLSX in process, paged. |
|
|
129
129
|
| [`file-open`](./extensions/file-open/) | `/open`, `open_path` | Open or reveal a file or directory in the OS-native application. |
|
|
130
130
|
| [`wechat`](./extensions/wechat/) | `/wechat`, `send_wechat` | Bridge a WeChat chat to the live session over the Weixin iLink bot API; inbound text, images, and files become turns. |
|
|
131
131
|
|
|
@@ -145,6 +145,7 @@ advertised to the model, and its instructions load only when the task matches
|
|
|
145
145
|
|---|---|
|
|
146
146
|
| [`init`](./skills/init/SKILL.md) | Creates or updates a project's `AGENTS.md` through a built-in interactive interview and plan review, from repository evidence. |
|
|
147
147
|
| [`refactor`](./skills/refactor/SKILL.md) | Audits a project or path for refactoring opportunities: duplication, oversized modules, coupling, drift, and high-churn code with weak tests. Returns a ranked shortlist with evidence and verification commands; discovery is read-only. |
|
|
148
|
+
| [`changelog`](./skills/changelog/SKILL.md) | Drafts the candidate bullet before implementation, records one user-visible bullet in the same commit, audits commits since the last tag for missing or weak entries, and curates a release section from the project's own rules. |
|
|
148
149
|
|
|
149
150
|
### Themes
|
|
150
151
|
|
package/README.zh-CN.md
CHANGED
|
@@ -37,7 +37,7 @@ Pi 提供一个精简而锐利的内核。这个包是在其之上的一层,
|
|
|
37
37
|
- **绝不搞乱检出区。** 隔离只需一条命令:任务切到自己分支的 `git worktree` 中,
|
|
38
38
|
每次提示还会生成快照,因此一次糟糕的回合只需一个 `/rewind` 就能回退。
|
|
39
39
|
- **跨会话记忆。** 持久笔记以纯 Markdown 保存,可读、可改、可纳入版本控制。
|
|
40
|
-
- **连通网络与文件。**
|
|
40
|
+
- **连通网络与文件。** 在会话内搜索、抓取、浏览、打开和读取文档与表格,还可通过桥接
|
|
41
41
|
在微信里直接回答当前会话。
|
|
42
42
|
|
|
43
43
|
一切都是可选的,且可独立开关。没有任何东西被分叉,也没有修改已安装的 Pi 文件:
|
|
@@ -64,9 +64,9 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
64
64
|
|
|
65
65
|
- `/bytefly [extension] [refresh]` 打开控制中心的 Extensions 区,列出每个已加载扩展
|
|
66
66
|
及其运行时健康状况,启用或禁用一个扩展,并用 `x` 清除项目级覆盖。
|
|
67
|
-
- `/bytefly settings` 打开控制中心的 Settings
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
- `/bytefly settings` 打开控制中心的 Settings 区:一次会话会改动的十四项设置排成
|
|
68
|
+
一列,值紧跟在名称之后;用 `Space`/`Enter` 修改,用 `Tab` 切换 Global/Project
|
|
69
|
+
作用域。其余键都是 `bytefly.json` 编辑,见配置参考。
|
|
70
70
|
- `/bytefly doctor [extension] [refresh]` 打印 doctor 报告(`run_doctor` 的文本),
|
|
71
71
|
检查每个已启用扩展在运行时是否具备所需条件。
|
|
72
72
|
- `/bytefly update` 立即重跑包更新检查,报告可更新的包、本包版本与 release URL,
|
|
@@ -81,7 +81,7 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
81
81
|
|
|
82
82
|
## 包含内容
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
18 个扩展、3 个随包技能,以及 2 个主题,按你想达成的目标分组。每个扩展自己的 `README.md`
|
|
85
85
|
提供完整的工具与命令说明。
|
|
86
86
|
|
|
87
87
|
### 规划与委派
|
|
@@ -96,6 +96,7 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
96
96
|
| [`question`](./extensions/question/) | `ask_user_question` | 向你提出一个或多个结构化问题(带标签的选项外加自由填写的“其他”)并等待回答。 |
|
|
97
97
|
| [`job`](./extensions/job/) | `job`, `/jobs` | 在后台运行长时 shell 命令;查看日志、等待或结束它们。 |
|
|
98
98
|
| [`watch`](./extensions/watch/) | `watch`, `/watch` | 跟踪文件或命令输出,按模式匹配行,并提醒你或把匹配的行交给智能体。 |
|
|
99
|
+
| [`context`](./extensions/context/) | `/context` | 显示上下文窗口的去向 —— 系统提示、工具定义、按角色拆分的对话、注入的笔记 —— 并从报告中触发压缩,给出压缩前后的数字。 |
|
|
99
100
|
|
|
100
101
|
### 保护你的工作
|
|
101
102
|
|
|
@@ -110,8 +111,8 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
110
111
|
| 扩展 | 工具与命令 | 说明 |
|
|
111
112
|
|---|---|---|
|
|
112
113
|
| [`web-access`](./extensions/web-access/) | `web_search`, `web_fetch` | 搜索网络(默认无密钥的 DuckDuckGo,可选 SearXNG 或 Brave),并把页面抓取为可读文本,支持分页、`find`、逐跳 SSRF 检查以及可选的 PDF 支持。 |
|
|
113
|
-
| [`file-browse`](./extensions/file-browse/) | `/browse` | 启动一个以工作目录为根的本地回环、只读文件浏览器,带 Markdown
|
|
114
|
-
| [`
|
|
114
|
+
| [`file-browse`](./extensions/file-browse/) | `/browse` | 启动一个以工作目录为根的本地回环、只读文件浏览器,带 Markdown 预览、模糊快速打开面板,以及为常开页面提供的实时状态。 |
|
|
115
|
+
| [`file-read`](./extensions/file-read/) | `read_doc` | 在进程内从本地 PDF、DOCX、DOC、ODT、RTF 或 XLSX 提取文本,支持分页。 |
|
|
115
116
|
| [`file-open`](./extensions/file-open/) | `/open`, `open_path` | 用操作系统原生应用打开或定位文件/目录。 |
|
|
116
117
|
| [`wechat`](./extensions/wechat/) | `/wechat`, `send_wechat` | 通过微信 iLink 机器人 API 把微信聊天桥接到实时会话;入站文本、图片和文件会变成回合。 |
|
|
117
118
|
|
|
@@ -129,6 +130,7 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
129
130
|
|---|---|
|
|
130
131
|
| [`init`](./skills/init/SKILL.md) | 基于仓库证据,通过内置的交互式访谈和计划审阅创建或更新项目的 `AGENTS.md`。 |
|
|
131
132
|
| [`refactor`](./skills/refactor/SKILL.md) | 审计项目或路径中的重构机会:重复代码、过大的模块、耦合、结构漂移,以及测试薄弱且改动频繁的代码。返回带证据和验证命令的排序清单;发现阶段只读。 |
|
|
133
|
+
| [`changelog`](./skills/changelog/SKILL.md) | 实现前先起草候选条目,实施后在同一次提交中记录一条用户可见的变更,审计上一个 tag 以来缺失或薄弱的条目,并按项目自己的规则整理发布段落。 |
|
|
132
134
|
|
|
133
135
|
### 主题
|
|
134
136
|
|
|
@@ -217,7 +217,10 @@ job · 2 background jobs finished
|
|
|
217
217
|
```
|
|
218
218
|
|
|
219
219
|
The rail is painted by the notice's worst severity, so a failure reads red at the
|
|
220
|
-
edge like an errored tool result
|
|
220
|
+
edge like an errored tool result, and the headline's title takes the notice's own
|
|
221
|
+
severity — a warning reads yellow where its sentence is, while an `info` or `ok`
|
|
222
|
+
notice stays body text. A row's label stays body text too: its severity is the
|
|
223
|
+
glyph it hangs on, so one failing row never tints the rest of the list.
|
|
221
224
|
|
|
222
225
|
`job` and `watch` post one when a background job finishes or a watched line
|
|
223
226
|
matches, so the report the model reads is visible too. `doctor` posts one when a
|
|
@@ -336,7 +339,7 @@ failed read is silent and not cached, so the next session tries again; see
|
|
|
336
339
|
| Command | What it does |
|
|
337
340
|
|---|---|
|
|
338
341
|
| `/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. |
|
|
339
|
-
| `/bytefly settings` | Open the control center on Settings. Outside `tui` it prints
|
|
342
|
+
| `/bytefly settings` | Open the control center on Settings. Outside `tui` it prints one `Label: Value` line per setting. |
|
|
340
343
|
| `/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. |
|
|
341
344
|
| `/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. |
|
|
342
345
|
|
|
@@ -355,7 +358,7 @@ print the grouped listing with a per-row health suffix and the headline, or that
|
|
|
355
358
|
extension's full findings when one is named. In `tui` the screen opens on the
|
|
356
359
|
session's cached report and probes on the first Extensions view; the text modes
|
|
357
360
|
probe before they print. `/bytefly settings` prints the
|
|
358
|
-
|
|
361
|
+
flat settings listing with each row's value outside `tui`; it does not
|
|
359
362
|
resolve packages or probe the doctor. The
|
|
360
363
|
proactive session-start check posts a transcript notice through the shared
|
|
361
364
|
`my-pi-agent/notice` renderer rather than a transient notification, and is
|
|
@@ -499,7 +502,7 @@ it with its own rates for the models they match:
|
|
|
499
502
|
For example, DeepSeek flash at `¥2` in and `¥8` out per million, with the
|
|
500
503
|
published peak windows and `offPeakMultiplier: 0.5`, prices a 1M-in + 1M-out
|
|
501
504
|
turn at `¥10.00` at peak and `¥5.00` off-peak. That example is worked end to end
|
|
502
|
-
in [`footer/
|
|
505
|
+
in [`footer/footer.test.ts`](./footer/footer.test.ts), which also prices the built-in
|
|
503
506
|
table with no config file at all.
|
|
504
507
|
|
|
505
508
|
## Content and colors
|
|
@@ -642,92 +645,59 @@ installs or fetches a package.
|
|
|
642
645
|
without leaving the session.
|
|
643
646
|
|
|
644
647
|
**Settings.** The second section uses the same frame and the same `Tab` scope
|
|
645
|
-
switch, with its own cursor. It
|
|
648
|
+
switch, with its own cursor. It is the shortlist a session changes: fourteen
|
|
649
|
+
preferences on one flat line each, the value beside its label, and no group
|
|
650
|
+
headings. The whole list fits a 24-row terminal, and the frame stops growing
|
|
651
|
+
there however tall the terminal is.
|
|
646
652
|
|
|
647
653
|
```
|
|
648
654
|
bytefly ──────────────────────────────────────────────────────────────
|
|
649
|
-
Extensions · Settings Global ·
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
◼
|
|
656
|
-
◼
|
|
657
|
-
◼
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
◼ Proactive health check
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
Cost decimals 2
|
|
667
|
-
Session budget 0
|
|
668
|
-
Transcript (3)
|
|
669
|
-
Rail glyph ╎
|
|
670
|
-
Achieved goal Hide
|
|
671
|
-
Output padding 1
|
|
672
|
-
Terminal (2)
|
|
673
|
-
Theme system
|
|
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
|
|
655
|
+
Extensions · Settings Global · 14 settings
|
|
656
|
+
|
|
657
|
+
❯ ◻ Bytefly startup TUI Off
|
|
658
|
+
◼ Theme system
|
|
659
|
+
◻ Desktop notifications Off
|
|
660
|
+
◼ Turn finished On
|
|
661
|
+
◼ Needs input On
|
|
662
|
+
◼ Job finished On
|
|
663
|
+
◼ Watcher matched On
|
|
664
|
+
Delivery method Auto
|
|
665
|
+
◻ Wake when a job finishes Off
|
|
666
|
+
◻ Wake on a match Off
|
|
667
|
+
◼ Automatic snapshots On
|
|
668
|
+
◼ Proactive health check On
|
|
669
|
+
Currency CNY (¥)
|
|
670
|
+
Session budget 0
|
|
671
|
+
|
|
690
672
|
Bytefly startup TUI — Pi setting
|
|
691
673
|
Use bytefly's startup header in place of Pi's startup TUI.
|
|
692
674
|
Default · ~/.pi/agent/settings.json
|
|
693
675
|
|
|
694
|
-
Esc close · ←/→ · Space change · Tab scope · u reset · J JSON ·
|
|
676
|
+
Esc close · ←/→ · Space change · Tab scope · u reset · J JSON · ↑/↓ select
|
|
695
677
|
```
|
|
696
678
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
|
700
|
-
|
|
701
|
-
|
|
|
702
|
-
|
|
|
703
|
-
|
|
|
704
|
-
|
|
|
705
|
-
|
|
|
706
|
-
|
|
|
707
|
-
|
|
|
708
|
-
|
|
|
709
|
-
|
|
|
710
|
-
|
|
|
711
|
-
|
|
|
712
|
-
|
|
|
713
|
-
|
|
|
714
|
-
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
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 |
|
|
728
|
-
|
|
729
|
-
Choosing **Currency** also writes that currency's default precision. Both rows
|
|
730
|
-
stay editable afterwards, so the footer follows the explicit values.
|
|
679
|
+
<img src="../../assets/bytefly-settings.png" alt="The /bytefly Settings section: one flat list of fourteen preferences with each value beside its label, the `Global · 14 settings` counts, and a three-row detail pane naming the focused row's source, description, and file" width="100%">
|
|
680
|
+
|
|
681
|
+
| Row | Source | Values |
|
|
682
|
+
|---|---|---|
|
|
683
|
+
| Bytefly startup TUI | Pi `settings.json` (`quietStartup`) | Off, On |
|
|
684
|
+
| Theme | Pi `settings.json` (`theme`) | `system`, `bytefly-dark`, `bytefly-light` |
|
|
685
|
+
| Desktop notifications | `notify.enabled` | Off, On |
|
|
686
|
+
| Turn finished | `notify.turnFinished` | Off, On |
|
|
687
|
+
| Needs input | `notify.needsInput` | Off, On |
|
|
688
|
+
| Job finished | `notify.jobFinished` | Off, On |
|
|
689
|
+
| Watcher matched | `notify.matchFound` | Off, On |
|
|
690
|
+
| Delivery method | `notify.method` | Auto, OSC 777, OSC 99, Windows toast, macOS, Linux |
|
|
691
|
+
| Wake when a job finishes | `job.wakeOnFinish` | Off, On |
|
|
692
|
+
| Wake on a match | `watch.wakeOnMatch` | Off, On |
|
|
693
|
+
| Automatic snapshots | `rewind.autoSnapshots` | Off, On |
|
|
694
|
+
| Proactive health check | `doctor.proactive` | Off, On |
|
|
695
|
+
| Currency | `price.currency.code` | CNY, USD |
|
|
696
|
+
| Session budget | `price.budget` | Number, `0` = off |
|
|
697
|
+
|
|
698
|
+
Choosing **Currency** also writes that currency's default precision
|
|
699
|
+
(`price.currency.decimals`). Both stay editable in `bytefly.json` afterwards, so
|
|
700
|
+
the footer follows the explicit values.
|
|
731
701
|
|
|
732
702
|
The **Theme** row lists `system` first, then the palettes this package ships,
|
|
733
703
|
`bytefly-dark` and `bytefly-light`; it cycles no further, so a bytefly screen
|
|
@@ -739,24 +709,34 @@ and is replaced by the next choice here, so manage those in Pi's `/settings` →
|
|
|
739
709
|
**Theme**.
|
|
740
710
|
|
|
741
711
|
`Space` (or `Enter`) changes the focused row: a boolean toggles, an enum cycles
|
|
742
|
-
forward, and
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
the source, describes the preference, and shows
|
|
750
|
-
where the value comes from — `Global · ~/.pi/agent/bytefly.json`, `Project ·
|
|
712
|
+
forward, and the one text row — **Session budget** — opens an inline editor on its
|
|
713
|
+
amount. `u` deletes the focused row's key so its default applies again (`Already
|
|
714
|
+
at its default.` when nothing is stored in that scope; an inherited Project value
|
|
715
|
+
says so instead), and `J` swaps the detail pane for the focused row's whole
|
|
716
|
+
section as the active scope stores it — the only view of the keys this screen
|
|
717
|
+
leaves to JSON. The detail pane names the source, describes the preference, and
|
|
718
|
+
shows where the value comes from — `Global · ~/.pi/agent/bytefly.json`, `Project ·
|
|
751
719
|
.pi/bytefly.json`, `Inherited from Global · ~/.pi/agent/bytefly.json`, or
|
|
752
720
|
`Default · <the active scope's file>`; an app row names the personal
|
|
753
721
|
`settings.json`. A successful change marks the screen `Saved · reload to apply`
|
|
754
722
|
— even when the terminal is too short for the detail body — and closing offers
|
|
755
723
|
the same reload confirm as an extension toggle.
|
|
756
724
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
725
|
+
The list is capped at fourteen rows so the screen keeps fitting a 24-row
|
|
726
|
+
terminal: adding a setting means removing one (`panel/panel.test.ts` holds the
|
|
727
|
+
ceiling). Everything else stays in `bytefly.json` — the tuning numbers, the
|
|
728
|
+
cosmetic labels, and the Pi preferences Pi's own `/settings` owns — and
|
|
729
|
+
`test/settings-coverage.test.ts` keeps the split honest: every loader key is
|
|
730
|
+
either a row or a declared JSON-only edit with the reason it left. Four
|
|
731
|
+
`bytefly.json` sections therefore have no row at all (`chrome`, `goal`,
|
|
732
|
+
`worktree`, `memory`), as do `notify.title`, `doctor.timeoutMs`,
|
|
733
|
+
`price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`, and
|
|
734
|
+
`job.detachedByDefault` inside sections that do. Each is documented in
|
|
735
|
+
[`docs/configuration.md`](../../docs/configuration.md).
|
|
736
|
+
|
|
737
|
+
Three of the six sections belong to other extensions (`rewind`, `job`, and
|
|
738
|
+
`watch`). The screen cannot import their normalizers, so it reports the leaf as
|
|
739
|
+
the file states it and declares the loader's default; the same test holds the
|
|
760
740
|
catalogue to every loader's defaults and bounds in both directions.
|
|
761
741
|
|
|
762
742
|
**Bytefly startup TUI** is the one row whose label differs from the Pi key it
|
|
@@ -767,31 +747,28 @@ with `true` or `false`.
|
|
|
767
747
|
|
|
768
748
|
App rows are **Global only**: Pi's setters for them write the personal
|
|
769
749
|
`settings.json`, and only resource paths have public project setters. Project
|
|
770
|
-
scope therefore lists the
|
|
750
|
+
scope therefore lists the twelve `bytefly.json` rows and a
|
|
771
751
|
`App settings are Global only.` note rather than promising a write that cannot
|
|
772
752
|
happen. A `bytefly.json` row writes one leaf in the selected scope (a depth-1
|
|
773
|
-
key, or a nested one such as `price.currency.
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
753
|
+
key, or a nested one such as `price.currency.code`) through a per-key writer, so
|
|
754
|
+
every sibling key, section, `$schema`, and `version` is preserved. A malformed
|
|
755
|
+
document is refused with a notice instead of overwritten, and `u` removes that
|
|
756
|
+
one leaf through the same writer's `unsetConfigValueAt`.
|
|
777
757
|
|
|
778
|
-
The non-`tui` form prints the headline
|
|
758
|
+
The non-`tui` form prints the headline and one `Label: Value` row per line, in
|
|
759
|
+
screen order:
|
|
779
760
|
|
|
780
761
|
```
|
|
781
|
-
bytefly: Settings · Global ·
|
|
782
|
-
|
|
783
|
-
Startup (1)
|
|
762
|
+
bytefly: Settings · Global · 14 settings
|
|
784
763
|
Bytefly startup TUI: Off
|
|
785
|
-
|
|
786
|
-
Notifications (7)
|
|
764
|
+
Theme: system
|
|
787
765
|
Desktop notifications: Off
|
|
788
766
|
Turn finished: On
|
|
789
767
|
Needs input: On
|
|
790
768
|
Job finished: On
|
|
791
769
|
Watcher matched: On
|
|
792
770
|
Delivery method: Auto
|
|
793
|
-
|
|
794
|
-
...
|
|
771
|
+
...
|
|
795
772
|
```
|
|
796
773
|
|
|
797
774
|
The doctor side probes every declared extension and reports each check as `ok`,
|
|
@@ -1004,12 +981,17 @@ command.
|
|
|
1004
981
|
- **Project overrides of app settings are not shown.** App rows read the
|
|
1005
982
|
personal file; a `.pi/settings.json` override still wins at runtime, and
|
|
1006
983
|
`pi config` is the place to manage it.
|
|
1007
|
-
- **
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
984
|
+
- **The list is a shortlist, not the whole document.** A row is one boolean,
|
|
985
|
+
enum, string, or number; the tuning numbers, the labels, and the Pi
|
|
986
|
+
preferences `/settings` owns stay in their files, and the catalogue is capped
|
|
987
|
+
at fourteen rows so the screen fits a 24-row terminal. `doctor.skip` (an
|
|
988
|
+
array), the `rates` table, and `price.peak` (a nested object) could never be a
|
|
989
|
+
row; the rest are declared JSON-only with their reason in
|
|
990
|
+
`test/settings-coverage.test.ts`.
|
|
991
|
+
- **The rail glyph is typed in `bytefly.json`.** It must be exactly one column,
|
|
1011
992
|
because a two-column glyph would push every railed body one cell right; the
|
|
1012
|
-
former four-glyph menu is
|
|
993
|
+
loader drops anything else, and the former four-glyph menu is the
|
|
994
|
+
configuration reference's example list.
|
|
1013
995
|
- **`doctor`, `settings`, and `update` are reserved first arguments.**
|
|
1014
996
|
`/bytefly doctor` always selects the report, so an extension literally named
|
|
1015
997
|
`doctor` cannot be narrowed to by name; `settings` and `update` are reserved
|
|
@@ -1134,9 +1116,9 @@ rather than showing a wrong value.
|
|
|
1134
1116
|
| 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. |
|
|
1135
1117
|
| Footer | `ctx.ui.setFooter` with a custom component, replacing Pi's built-in footer; installed only when `ctx.mode === "tui"`. |
|
|
1136
1118
|
| 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. |
|
|
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. |
|
|
1119
|
+
| Notice | `registerMessageRenderer(NOTICE_TYPE)` draws every shared transcript notice at the margin from its `details`; the headline stays at the margin with its title painted by the notice's own severity, and its rows hang from the transcript rail, painted by the notice's worst severity, whose glyph comes from the shared `RailSource`. `job` and `watch` post one when their work settles, and `doctor` posts one at `session_start` for a missing hard requirement. The type and shape come from `lib/notice.ts`. A message without `details` falls back to Pi's default custom-message box. |
|
|
1138
1120
|
| 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. |
|
|
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
|
|
1121
|
+
| 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 flat 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. |
|
|
1140
1122
|
| 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
1123
|
| 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. |
|
|
1142
1124
|
| 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. |
|
|
@@ -1344,7 +1326,7 @@ rather than showing a wrong value.
|
|
|
1344
1326
|
a third layer.** An extension cannot import another extension's modules, so
|
|
1345
1327
|
the only legal home for a shared prerequisite table is `lib/requirements.ts`;
|
|
1346
1328
|
the report itself is a pure function of the probe results.
|
|
1347
|
-
- **The install hint has one home.** `
|
|
1329
|
+
- **The install hint has one home.** `file-read` and `web-access` format their
|
|
1348
1330
|
tool errors from the same `REQUIREMENTS` entries `doctor` prints, so a user
|
|
1349
1331
|
reads the same command whether a tool failed or the report named it.
|
|
1350
1332
|
- **Settings are a curated table, not a schema walker.** The rows cover every
|
|
@@ -1456,8 +1438,8 @@ columns, gauge), so the look follows the active theme.
|
|
|
1456
1438
|
| `working/register.ts` | Starts the tick on `turn_start`, tracks top-level tools on `tool_execution_start`, and cancels on `agent_end`/`session_shutdown`. |
|
|
1457
1439
|
| `panel/types.ts` | `PanelSection` (`extensions` | `settings`), `PanelRow`, and `PanelModel`, the merged row model. |
|
|
1458
1440
|
| `panel/join.ts` | The item/report union with the unambiguous-name health rule and unique row keys, groups, and ordering. |
|
|
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
|
|
1460
|
-
| `panel/settings.ts` | The curated Settings catalogue: descriptors, snapshot views and origins, value cycling, stored-value mapping, validation,
|
|
1441
|
+
| `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 flat Settings listing. |
|
|
1442
|
+
| `panel/settings.ts` | The curated Settings catalogue: the fourteen descriptors in screen order, snapshot views and origins, value cycling, stored-value mapping, validation, plus the per-section readers that resolve a row's leaf over the global and project documents. |
|
|
1461
1443
|
| `panel/settings-runtime.ts` | The Settings runtime: snapshot cache, scope guards, app setters, per-leaf `bytefly.json` writes, dirty state, and change listeners. |
|
|
1462
1444
|
| `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
1445
|
| `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`. |
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
* — so it goes through `sanitizeLine` before it reaches the terminal, and every
|
|
8
8
|
* line is clipped to the width it is given. The rail is painted by the notice's
|
|
9
9
|
* worst severity, so a failure reads red at the edge like an errored tool
|
|
10
|
-
* result
|
|
10
|
+
* result, and the headline's title is painted by the notice's own severity, so a
|
|
11
|
+
* warning reads yellow where its sentence is; the source name stays at the
|
|
12
|
+
* margin and a row's label stays body text behind its glyph.
|
|
11
13
|
*/
|
|
12
14
|
|
|
13
15
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
@@ -65,16 +67,16 @@ export function noticeLines(
|
|
|
65
67
|
glyph = DEFAULT_RAIL_GLYPH,
|
|
66
68
|
): string[] {
|
|
67
69
|
const w = Math.max(1, width);
|
|
70
|
+
const fallback = knownSeverity(details.severity, "info");
|
|
68
71
|
const sep = paint(theme, NOTICE_CONFIG.detailRole, SEPARATORS.item);
|
|
69
72
|
const source = paint(theme, NOTICE_CONFIG.sourceRole, sanitizeLine(details.source));
|
|
70
|
-
const title = paint(theme, NOTICE_CONFIG.
|
|
73
|
+
const title = paint(theme, NOTICE_CONFIG.titleRoles[fallback], sanitizeLine(details.title));
|
|
71
74
|
const items = details.items ?? [];
|
|
72
75
|
const shown = items.slice(0, NOTICE_CONFIG.maxItems);
|
|
73
|
-
const fallback = knownSeverity(details.severity, "info");
|
|
74
76
|
const gap = " ".repeat(GLYPH_GAP);
|
|
75
77
|
|
|
76
78
|
const rows = shown.map((item) => {
|
|
77
|
-
const label = paint(theme, NOTICE_CONFIG.
|
|
79
|
+
const label = paint(theme, NOTICE_CONFIG.rowRole, sanitizeLine(item.label));
|
|
78
80
|
const detail = item.detail ? `${sep}${paint(theme, NOTICE_CONFIG.detailRole, sanitizeLine(item.detail))}` : "";
|
|
79
81
|
return `${severityGlyph(theme, severityOf(item, fallback))}${gap}${label}${detail}`;
|
|
80
82
|
});
|
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
* glyph. The glyphs come from the shared vocabulary, the roles from the shared
|
|
7
7
|
* rail map, and the rail glyph from the `chrome` config, so a notice reads like
|
|
8
8
|
* the tool results around it.
|
|
9
|
+
*
|
|
10
|
+
* Severity reaches two surfaces: the rail (the block's worst severity) and the
|
|
11
|
+
* headline's title (the notice's own). A row carries no colour of its own, so a
|
|
12
|
+
* notice reporting one success and one failure stays readable as a list.
|
|
9
13
|
*/
|
|
10
14
|
|
|
11
15
|
import type { NoticeSeverity } from "../../../lib/notice.ts";
|
|
@@ -16,8 +20,18 @@ import { RAIL_ROLES } from "../chrome.ts";
|
|
|
16
20
|
export const NOTICE_CONFIG = {
|
|
17
21
|
/** Role for the source name at the head of the block. */
|
|
18
22
|
sourceRole: "accent" as TuiRole,
|
|
19
|
-
/**
|
|
20
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Role for the headline's title, keyed by the notice's own severity: an alert
|
|
25
|
+
* reads in colour where the sentence is, a routine notice stays body text.
|
|
26
|
+
*/
|
|
27
|
+
titleRoles: {
|
|
28
|
+
info: "label",
|
|
29
|
+
ok: "label",
|
|
30
|
+
warn: "warn",
|
|
31
|
+
bad: "bad",
|
|
32
|
+
} as Record<NoticeSeverity, TuiRole>,
|
|
33
|
+
/** Role for each row's label; a row states its severity with its glyph. */
|
|
34
|
+
rowRole: "label" as TuiRole,
|
|
21
35
|
/** Role for the `·` separators and each row's trailing detail. */
|
|
22
36
|
detailRole: "faint" as TuiRole,
|
|
23
37
|
/** Width-1 glyph per severity, from the shared vocabulary. */
|
|
@@ -18,7 +18,7 @@ import { sanitizeLine } from "../../../lib/format.ts";
|
|
|
18
18
|
import { GLYPHS } from "../../../lib/tui/glyphs.ts";
|
|
19
19
|
import type { TuiRole } from "../../../lib/tui/tokens.ts";
|
|
20
20
|
import { reportSeverity, reportSummary, severityGlyphChar, severityRole } from "../doctor/format.ts";
|
|
21
|
-
import {
|
|
21
|
+
import type { SettingView } from "./settings.ts";
|
|
22
22
|
import type { PanelModel, PanelRow, PanelSection } from "./types.ts";
|
|
23
23
|
|
|
24
24
|
/** The settings scope the screen shows. */
|
|
@@ -125,15 +125,10 @@ export function formatSettingsHeadline(count: number): string {
|
|
|
125
125
|
return `bytefly: Settings · Global · ${count} settings`;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
/** The
|
|
128
|
+
/** The Settings listing for non-TUI modes, one row per line, in screen order. */
|
|
129
129
|
export function formatSettingsListing(views: readonly SettingView[]): string {
|
|
130
130
|
const lines = [formatSettingsHeadline(views.length)];
|
|
131
|
-
for (const
|
|
132
|
-
lines.push("", `${group.label} (${group.views.length})`);
|
|
133
|
-
for (const view of group.views) {
|
|
134
|
-
lines.push(` ${sanitizeLine(view.label)}: ${sanitizeLine(view.valueLabel)}`);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
131
|
+
for (const view of views) lines.push(` ${sanitizeLine(view.label)}: ${sanitizeLine(view.valueLabel)}`);
|
|
137
132
|
return lines.join("\n");
|
|
138
133
|
}
|
|
139
134
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { basename, dirname } from "node:path";
|
|
22
22
|
import type { ExtensionReport } from "../../../lib/requirements.ts";
|
|
23
|
-
import { buildEntries } from "../picker/resources.ts";
|
|
23
|
+
import { buildEntries, resourceKey } from "../picker/resources.ts";
|
|
24
24
|
import type { ResourceItem } from "../picker/types.ts";
|
|
25
25
|
import type { PanelGroup, PanelModel, PanelRow } from "./types.ts";
|
|
26
26
|
|
|
@@ -29,11 +29,6 @@ export function extensionName(path: string): string {
|
|
|
29
29
|
return basename(dirname(path));
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
/** Unique identity of a resolved resource, independent of the directory name. */
|
|
33
|
-
export function resourceKey(item: ResourceItem): string {
|
|
34
|
-
return `${item.metadata.source}:${item.path}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
32
|
/** Row key for a report that has no resolved extension item. */
|
|
38
33
|
function reportKey(name: string): string {
|
|
39
34
|
return `report:${name}`;
|