@gavin-hu/my-pi-agent 0.17.0 → 0.18.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 +17 -9
- package/README.zh-CN.md +16 -9
- package/extensions/bytefly/README.md +25 -18
- package/extensions/bytefly/notify/types.ts +1 -1
- package/extensions/bytefly/panel/settings.ts +25 -18
- package/extensions/file-browse/README.md +60 -21
- package/extensions/file-browse/chrome.ts +83 -0
- package/extensions/file-browse/client.ts +62 -0
- package/extensions/file-browse/config.ts +12 -3
- package/extensions/file-browse/diff-html.ts +94 -0
- package/extensions/file-browse/html.ts +19 -147
- package/extensions/file-browse/live-client.ts +47 -1
- package/extensions/file-browse/live.ts +35 -14
- package/extensions/file-browse/rev.ts +42 -0
- package/extensions/file-browse/router.ts +25 -4
- package/extensions/file-browse/server.ts +7 -0
- package/extensions/file-browse/styles.ts +2 -0
- package/extensions/goal/plan-route.ts +8 -2
- package/extensions/job/README.md +7 -5
- package/extensions/job/index.ts +15 -7
- package/extensions/memory/README.md +3 -3
- package/extensions/plan/README.md +280 -86
- package/extensions/plan/commands.ts +56 -5
- package/extensions/plan/feedback.ts +300 -63
- package/extensions/plan/index.ts +1 -1
- package/extensions/plan/plan-index.ts +1 -1
- package/extensions/plan/plan-text.ts +18 -1
- package/extensions/plan/plans.ts +165 -57
- package/extensions/plan/review-prompt.ts +93 -0
- package/extensions/plan/review.ts +78 -98
- package/extensions/plan/runtime.ts +1 -1
- package/extensions/plan/split.ts +87 -0
- package/extensions/plan/steps.ts +80 -93
- package/extensions/plan/tools/enter.ts +8 -3
- package/extensions/plan/tools/exit.ts +101 -23
- package/extensions/plan/tools/write.ts +8 -3
- package/extensions/plan/tools.ts +1 -1
- package/extensions/plan/tui.ts +51 -8
- package/extensions/plan/types.ts +37 -3
- package/extensions/plan/web-chrome.ts +2 -1
- package/extensions/plan/web-client.ts +121 -177
- package/extensions/plan/web-collab.ts +207 -0
- package/extensions/plan/web-comments.ts +269 -0
- package/extensions/plan/web-page.ts +103 -17
- package/extensions/plan/web-router.ts +146 -30
- package/extensions/plan/web-share-session.ts +197 -0
- package/extensions/plan/web-share.ts +169 -0
- package/extensions/plan/web-streams.ts +124 -0
- package/extensions/plan/web-tokens.ts +63 -0
- package/extensions/plan/web.ts +193 -45
- package/extensions/question/README.md +3 -0
- package/extensions/question/dialogs.ts +91 -1
- package/extensions/question/tools.ts +2 -1
- package/extensions/session-bus/README.md +247 -0
- package/extensions/session-bus/commands.ts +165 -0
- package/extensions/session-bus/format.ts +124 -0
- package/extensions/session-bus/index.ts +69 -0
- package/extensions/session-bus/notice.ts +58 -0
- package/extensions/session-bus/protocol.ts +134 -0
- package/extensions/session-bus/result.ts +243 -0
- package/extensions/session-bus/rows.ts +169 -0
- package/extensions/session-bus/runtime.ts +575 -0
- package/extensions/session-bus/store.ts +329 -0
- package/extensions/session-bus/team.ts +102 -0
- package/extensions/session-bus/tools.ts +227 -0
- package/extensions/session-bus/tui.ts +394 -0
- package/extensions/session-bus/types.ts +98 -0
- package/extensions/subagent/README.md +1 -1
- package/extensions/watch/README.md +9 -5
- package/extensions/watch/index.ts +15 -9
- package/extensions/wechat/README.md +20 -33
- package/extensions/wechat/bridge.ts +8 -8
- package/extensions/wechat/commands.ts +2 -2
- package/extensions/wechat/deliver.ts +57 -37
- package/extensions/wechat/interaction.ts +31 -16
- package/extensions/wechat/notices.ts +7 -7
- package/extensions/wechat/peer-worker.ts +19 -34
- package/extensions/wechat/presence.ts +3 -4
- package/extensions/wechat/prompt.ts +39 -24
- package/extensions/wechat/reply-pipeline.ts +12 -4
- package/extensions/worktree/git.ts +5 -0
- package/extensions/worktree/registry.ts +11 -5
- package/extensions/worktree/status.ts +1 -3
- package/lib/README.md +6 -2
- package/lib/claims/overlap.ts +43 -0
- package/lib/http/router.ts +40 -13
- package/lib/http/server.ts +27 -13
- package/lib/interaction.ts +10 -0
- package/lib/notice.ts +29 -2
- package/lib/plan-entry.ts +7 -2
- package/lib/plans/sections.ts +172 -0
- package/lib/plans/setting.ts +52 -0
- package/lib/plans/split.ts +215 -0
- package/lib/plans/store.ts +19 -0
- package/lib/plans/team.ts +151 -0
- package/lib/qr.ts +64 -0
- package/lib/repo-key.ts +74 -0
- package/lib/report.ts +52 -33
- package/lib/requirements.ts +1 -2
- package/lib/tui/README.md +16 -2
- package/lib/tui/dock-screen.ts +85 -17
- package/lib/tui/line-pane.ts +15 -4
- package/lib/tui/tool.ts +23 -4
- package/lib/web/components.ts +1 -1
- package/package.json +3 -2
- package/skills/init/SKILL.md +80 -45
- package/skills/init/references/agents-md-quality.md +26 -2
- package/skills/init/references/interview-questions.md +36 -14
- package/skills/next/SKILL.md +78 -53
- package/skills/parallel-dev/SKILL.md +150 -0
- package/extensions/plan/config.ts +0 -27
- package/extensions/wechat/qrcode.ts +0 -46
package/README.md
CHANGED
|
@@ -36,7 +36,8 @@ want the agent to *think first and work safely*:
|
|
|
36
36
|
plan file that the agent then follows step by step.
|
|
37
37
|
- **Delegate and parallelize.** Run specialist subagents in their own Pi
|
|
38
38
|
processes, push a long build into a background job, and let a watcher tail a
|
|
39
|
-
log until it matters —
|
|
39
|
+
log until it matters — then run several sessions on one repository through a
|
|
40
|
+
shared bus, each owning its slice, all while you keep the thread.
|
|
40
41
|
- **Never wreck the checkout.** Isolation is one command: the task moves onto its
|
|
41
42
|
own branch in a `git worktree`, and every prompt is snapshotted so a bad turn
|
|
42
43
|
is one `/rewind` away.
|
|
@@ -47,7 +48,7 @@ want the agent to *think first and work safely*:
|
|
|
47
48
|
through a bridge to the live session.
|
|
48
49
|
|
|
49
50
|
Everything is optional and independently toggleable. Nothing is forked, and no
|
|
50
|
-
installed Pi file is
|
|
51
|
+
installed Pi file is written to: Pi discovers the resources through the `pi`
|
|
51
52
|
manifest in [`package.json`](./package.json), so the package upgrades with Pi
|
|
52
53
|
like any other.
|
|
53
54
|
|
|
@@ -86,7 +87,8 @@ Then, from inside Pi:
|
|
|
86
87
|
- `/bytefly update` re-runs the package update check now and reports the
|
|
87
88
|
updateable packages, this package's version and release URL, or a skip.
|
|
88
89
|
- `/plan <task>` starts a task in read-only planning mode.
|
|
89
|
-
- `/skill:init` creates or updates
|
|
90
|
+
- `/skill:init` creates or updates the instruction file Pi reads through a short
|
|
91
|
+
built-in interview and a plan you review first.
|
|
90
92
|
|
|
91
93
|
One thing the pack does on its own: once per interactive session, `bytefly`
|
|
92
94
|
asks Pi's package manager which configured packages are behind, suppresses Pi's
|
|
@@ -99,14 +101,14 @@ and `PI_OFFLINE` skips the check;
|
|
|
99
101
|
|
|
100
102
|
## What you get
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
19 extensions, 5 packaged skills, and 2 themes, grouped by what you are trying
|
|
103
105
|
to do. Each extension's own `README.md` has the full tool and command surface.
|
|
104
106
|
|
|
105
107
|
### Plan and delegate
|
|
106
108
|
|
|
107
109
|
| Extension | Tools and commands | What it does |
|
|
108
110
|
|---|---|---|
|
|
109
|
-
| [`plan`](./extensions/plan/) | `enter_plan_mode`, `write_plan`, `exit_plan_mode`, `cancel_plan_mode`, `set_plan_steps`, `/plan`, `--plan` | Read-only planning: the model investigates, saves a plan under
|
|
111
|
+
| [`plan`](./extensions/plan/) | `enter_plan_mode`, `write_plan`, `exit_plan_mode`, `cancel_plan_mode`, `set_plan_steps`, `/plan`, `--plan` | Read-only planning: the model investigates, saves a plan under `~/.pi/agent/plans/<repo-key>` — one store per repository, shared by its worktrees — and you approve it before anything is written; with `plan.split` on, the approval can also split it into slices that separate sessions join by name. Review in the TUI, or open it in a browser to leave inline comments: the page follows the plan file live, and you can hand one reviewer link per teammate so each comments under their own name. The `init` skill uses the same review to create or update a project's `AGENTS.md`. |
|
|
110
112
|
| [`check`](./extensions/check/) | `run_check`, `/check` | Detect the project's test, lint, or typecheck command (or take `check.command`), run it in a supervised process, and turn failures into a navigable `file:line` list. |
|
|
111
113
|
| [`subagent`](./extensions/subagent/) | `subagent`, `/agents` | Delegate a task to a specialist agent (`explorer`, `planner`, `reviewer`, `worker`, `researcher`, `tester`, `debugger`, `documenter`) in its own Pi process — single, parallel, chained, or in the background, with a footer chip while it runs and a finish notice. |
|
|
112
114
|
| [`todo`](./extensions/todo/) | `todo`, `/todos` | A persistent task list (`pending` / `in_progress` / `completed`) with a one-line widget. |
|
|
@@ -114,6 +116,7 @@ to do. Each extension's own `README.md` has the full tool and command surface.
|
|
|
114
116
|
| [`question`](./extensions/question/) | `ask_user_question` | Ask you one or more structured questions (labelled options plus free-form "Other") and wait. |
|
|
115
117
|
| [`job`](./extensions/job/) | `job`, `/jobs` | Run long-lived shell commands in the background; inspect logs, wait, or kill them. |
|
|
116
118
|
| [`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. |
|
|
119
|
+
| [`session-bus`](./extensions/session-bus/) | `session`, `/sessions` (screen) | Coordinate parallel Pi sessions on one repository: discover peers, exchange short messages/events, consume an inbox, join a slice of an approved split or claim paths before editing, with `/sessions` as a live board of peers, unread mail, and claims. Local, pull-based by default, with an opt-in inbox watch that raises this session's turn once it is idle; it never spawns an agent. |
|
|
117
120
|
| [`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. |
|
|
118
121
|
|
|
119
122
|
### Keep your work safe
|
|
@@ -129,7 +132,7 @@ to do. Each extension's own `README.md` has the full tool and command surface.
|
|
|
129
132
|
| Extension | Tools and commands | What it does |
|
|
130
133
|
|---|---|---|
|
|
131
134
|
| [`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. |
|
|
132
|
-
| [`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,
|
|
135
|
+
| [`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, a `path:12-30` reference copied from a selection, live status for a page left open, and a reload hint when the folder it lists changes. |
|
|
133
136
|
| [`file-read`](./extensions/file-read/) | `read_doc` | Extract text from a local PDF, DOCX, DOC, ODT, RTF, or XLSX in process, paged. |
|
|
134
137
|
| [`file-open`](./extensions/file-open/) | `/open`, `open_path` | Open or reveal a file or directory in the OS-native application. |
|
|
135
138
|
| [`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. |
|
|
@@ -148,10 +151,11 @@ advertised to the model, and its instructions load only when the task matches
|
|
|
148
151
|
|
|
149
152
|
| Skill | What it does |
|
|
150
153
|
|---|---|
|
|
151
|
-
| [`init`](./skills/init/SKILL.md) | Creates or updates
|
|
154
|
+
| [`init`](./skills/init/SKILL.md) | Creates or updates the instruction file Pi actually reads (`AGENTS.md`, or `AGENTS.override.md` when it shadows it) through a built-in interactive interview and plan review, deriving commands, generated paths, packages, and purpose from repository evidence. |
|
|
152
155
|
| [`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. |
|
|
153
156
|
| [`changelog`](./skills/changelog/SKILL.md) | Records one user-visible bullet in the same commit as the change, audits commits since the last tag for missing or weak entries, and curates a release section from the project's own rules. |
|
|
154
|
-
| [`
|
|
157
|
+
| [`parallel-dev`](./skills/parallel-dev/SKILL.md) | Runs parallel development as a lead and a team: a lead accountable for the contract, shared files, merge order and a green baseline who also owns a workstream, one owner per disjoint workstream, a walking skeleton first, advisory path claims, a turn-boundary protocol, and independent verification. |
|
|
158
|
+
| [`next`](./skills/next/SKILL.md) | Suggests the next todos by priority — loose work, a broken or unfinished promise — from this conversation once it has done work, and from the tree only when it is empty, with the words and a path after the command saying what to ask and where to look. Read-only, and capped at a short numbered list with evidence and the command that starts each. |
|
|
155
159
|
|
|
156
160
|
### Themes
|
|
157
161
|
|
|
@@ -174,6 +178,10 @@ README use `bytefly-dark`.
|
|
|
174
178
|
<td width="50%"><img src="assets/job.png" alt="The /jobs screen: a summary line, the job rows with status glyphs and elapsed times, and the focused job's command, cwd, and last output line" width="100%"></td>
|
|
175
179
|
<td width="50%"><img src="assets/rewind.png" alt="The /rewind screen: prompt rows newest first, a diamond marking prompts with a code snapshot, and the focused prompt's snapshot detail" width="100%"></td>
|
|
176
180
|
</tr>
|
|
181
|
+
<tr>
|
|
182
|
+
<td width="50%"><img src="assets/session.png" alt="The /sessions screen: a counts summary, session rows with unread and claim counts, the focused session's cwd, claims, and identity, and the Tab scope and watch hints" width="100%"></td>
|
|
183
|
+
<td width="50%"><img src="assets/watch.png" alt="The /watch screen: a summary line and watcher rows with live match counts and the focused watcher's pattern and source" width="100%"></td>
|
|
184
|
+
</tr>
|
|
177
185
|
</table>
|
|
178
186
|
|
|
179
187
|
### Tool renderings
|
|
@@ -184,7 +192,7 @@ each tool's own renderer (or bytefly's generic fallback): the user nameplate and
|
|
|
184
192
|
a notice, Pi's built-ins, and every tool this package registers. The rail glyph
|
|
185
193
|
is the `chrome.rail` setting.
|
|
186
194
|
|
|
187
|
-

|
|
195
|
+

|
|
188
196
|
|
|
189
197
|
`bun run screenshot:tools` regenerates it; `bun run screenshot:tool-pngs` writes
|
|
190
198
|
one image per tool under [`assets/tools/`](./assets/tools).
|
package/README.zh-CN.md
CHANGED
|
@@ -33,14 +33,15 @@ Pi 提供一个精简而锐利的内核。这个包是在其之上的一层,
|
|
|
33
33
|
- **先规划,再执行。** 只读的规划模式把一次任务变成一份可审阅的计划文件,智能体
|
|
34
34
|
随后按步骤执行。
|
|
35
35
|
- **委派与并行。** 在各自的 Pi 进程中运行专职子智能体,把耗时构建交给后台任务,
|
|
36
|
-
让 watcher
|
|
36
|
+
让 watcher 盯住日志直到出现关键行,还能让同一仓库上的多个会话通过共享总线协作、
|
|
37
|
+
各自负责自己的一摊 —— 你继续把握主线。
|
|
37
38
|
- **绝不搞乱检出区。** 隔离只需一条命令:任务切到自己分支的 `git worktree` 中,
|
|
38
39
|
每次提示还会生成快照,因此一次糟糕的回合只需一个 `/rewind` 就能回退。
|
|
39
40
|
- **跨会话记忆。** 持久笔记以纯 Markdown 保存,可读、可改、可纳入版本控制。
|
|
40
41
|
- **连通网络与文件。** 在会话内搜索、抓取、浏览、打开和读取文档与表格,还可通过桥接
|
|
41
42
|
在微信里直接回答当前会话。
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
一切都是可选的,且可独立开关。没有任何东西被分叉,也没有写入任何已安装的 Pi 文件:
|
|
44
45
|
Pi 通过 [`package.json`](./package.json) 里的 `pi` manifest 发现这些资源,因此
|
|
45
46
|
该包能像其他包一样随 Pi 一起升级。
|
|
46
47
|
|
|
@@ -74,7 +75,7 @@ Windows、macOS 和 Linux 均可运行,完整检查套件在每个平台上都
|
|
|
74
75
|
- `/bytefly update` 立即重跑包更新检查,报告可更新的包、本包版本与 release URL,
|
|
75
76
|
或跳过原因。
|
|
76
77
|
- `/plan <任务>` 以只读规划模式开始一个任务。
|
|
77
|
-
- `/skill:init` 通过内置的简短访谈和先审阅的计划创建或更新
|
|
78
|
+
- `/skill:init` 通过内置的简短访谈和先审阅的计划创建或更新 Pi 实际读取的指令文件。
|
|
78
79
|
|
|
79
80
|
还有一件包会自行做的事:每次交互式会话启动时,`bytefly` 询问 Pi 的包管理器
|
|
80
81
|
哪些已配置的包有更新,抑制 Pi 自己的启动更新块,并用主题化 notice 列出它们
|
|
@@ -85,14 +86,14 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
85
86
|
|
|
86
87
|
## 包含内容
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
19 个扩展、5 个随包技能,以及 2 个主题,按你想达成的目标分组。每个扩展自己的 `README.md`
|
|
89
90
|
提供完整的工具与命令说明。
|
|
90
91
|
|
|
91
92
|
### 规划与委派
|
|
92
93
|
|
|
93
94
|
| 扩展 | 工具与命令 | 说明 |
|
|
94
95
|
|---|---|---|
|
|
95
|
-
| [`plan`](./extensions/plan/) | `enter_plan_mode`, `write_plan`, `exit_plan_mode`, `cancel_plan_mode`, `set_plan_steps`, `/plan`, `--plan` | 只读规划:模型先调研,把计划保存到
|
|
96
|
+
| [`plan`](./extensions/plan/) | `enter_plan_mode`, `write_plan`, `exit_plan_mode`, `cancel_plan_mode`, `set_plan_steps`, `/plan`, `--plan` | 只读规划:模型先调研,把计划保存到 `~/.pi/agent/plans/<repo-key>` 下(每个仓库一份,各 worktree 共享),你在写入任何内容前先批准;开启 `plan.split` 后,批准时还可以把计划拆成切片,由独立会话按名字加入。可在 TUI 中审阅,或在浏览器中打开以留下行内评论:页面会跟随计划文件实时更新,你也可以给每位同事各一个审阅链接,各自以绑定的名义评论。`init` 技能复用同一审阅流程来创建或更新项目的 `AGENTS.md`。 |
|
|
96
97
|
| [`check`](./extensions/check/) | `run_check`, `/check` | 检测项目的测试、lint 或类型检查命令(或使用 `check.command`),在受监管的进程中运行,并把失败整理成可导航的 `file:line` 列表。 |
|
|
97
98
|
| [`subagent`](./extensions/subagent/) | `subagent`, `/agents` | 把任务委派给专职智能体(`explorer`、`planner`、`reviewer`、`worker`、`researcher`、`tester`、`debugger`、`documenter`),运行在它自己的 Pi 进程中 —— 单个、并行、链式或在后台运行;后台运行时在页脚显示数量,完成后发出提示。 |
|
|
98
99
|
| [`todo`](./extensions/todo/) | `todo`, `/todos` | 持久任务列表(`pending` / `in_progress` / `completed`),配一行式 widget。 |
|
|
@@ -100,6 +101,7 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
100
101
|
| [`question`](./extensions/question/) | `ask_user_question` | 向你提出一个或多个结构化问题(带标签的选项外加自由填写的“其他”)并等待回答。 |
|
|
101
102
|
| [`job`](./extensions/job/) | `job`, `/jobs` | 在后台运行长时 shell 命令;查看日志、等待或结束它们。 |
|
|
102
103
|
| [`watch`](./extensions/watch/) | `watch`, `/watch` | 跟踪文件或命令输出,按模式匹配行,并提醒你或把匹配的行交给智能体。 |
|
|
104
|
+
| [`session-bus`](./extensions/session-bus/) | `session`, `/sessions`(屏幕) | 在同一仓库的多个 Pi 会话之间协调:发现彼此、交换简短消息/事件、读取收件箱、加入已批准拆分中的一个切片或编辑前声明路径;`/sessions` 是显示对等会话、未读邮件和路径声明的实时面板。本地、默认拉取式;会话可以自行开启收件箱监视,在空闲时唤起本会话的一轮,从不创建智能体。 |
|
|
103
105
|
| [`context`](./extensions/context/) | `/context` | 显示上下文窗口的去向 —— 系统提示、工具定义、按角色拆分的对话、注入的笔记 —— 并从报告中触发压缩,给出压缩前后的数字。 |
|
|
104
106
|
|
|
105
107
|
### 保护你的工作
|
|
@@ -115,7 +117,7 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
115
117
|
| 扩展 | 工具与命令 | 说明 |
|
|
116
118
|
|---|---|---|
|
|
117
119
|
| [`web-access`](./extensions/web-access/) | `web_search`, `web_fetch` | 搜索网络(默认无密钥的 DuckDuckGo,可选 SearXNG 或 Brave),并把页面抓取为可读文本,支持分页、`find`、逐跳 SSRF 检查以及可选的 PDF 支持。 |
|
|
118
|
-
| [`file-browse`](./extensions/file-browse/) | `/browse` | 启动一个以工作目录为根的本地回环、只读文件浏览器,带 Markdown
|
|
120
|
+
| [`file-browse`](./extensions/file-browse/) | `/browse` | 启动一个以工作目录为根的本地回环、只读文件浏览器,带 Markdown 预览、模糊快速打开面板、从选区复制 `path:12-30` 引用、为常开页面提供的实时状态,以及所列目录变化时的重新加载提示。 |
|
|
119
121
|
| [`file-read`](./extensions/file-read/) | `read_doc` | 在进程内从本地 PDF、DOCX、DOC、ODT、RTF 或 XLSX 提取文本,支持分页。 |
|
|
120
122
|
| [`file-open`](./extensions/file-open/) | `/open`, `open_path` | 用操作系统原生应用打开或定位文件/目录。 |
|
|
121
123
|
| [`wechat`](./extensions/wechat/) | `/wechat`, `send_wechat` | 通过微信 iLink 机器人 API 把微信聊天桥接到实时会话;入站文本、图片和文件会变成回合。 |
|
|
@@ -132,10 +134,11 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
132
134
|
|
|
133
135
|
| 技能 | 说明 |
|
|
134
136
|
|---|---|
|
|
135
|
-
| [`init`](./skills/init/SKILL.md) |
|
|
137
|
+
| [`init`](./skills/init/SKILL.md) | 通过内置的交互式访谈和计划审阅,基于仓库证据创建或更新 Pi 实际读取的指令文件(`AGENTS.md`;存在覆盖它的 `AGENTS.override.md` 时则是该文件),并从仓库推导命令、生成路径与包范围。 |
|
|
136
138
|
| [`refactor`](./skills/refactor/SKILL.md) | 审计项目或路径中的重构机会:重复代码、过大的模块、耦合、结构漂移,以及测试薄弱且改动频繁的代码。返回带证据和验证命令的排序清单;发现阶段只读。 |
|
|
137
139
|
| [`changelog`](./skills/changelog/SKILL.md) | 在变更的同一次提交中记录一条用户可见的条目,审计上一个 tag 以来缺失或薄弱的条目,并按项目自己的规则整理发布段落。 |
|
|
138
|
-
| [`
|
|
140
|
+
| [`parallel-dev`](./skills/parallel-dev/SKILL.md) | 以“负责人加团队”的方式组织并行开发:负责人对契约、共享文件、合并顺序和绿色基线负责,同时自己承担一个工作流;每个互不重叠的工作流各有一名所有者,先做可运行的纵向骨架,声明路径,在每个回合的边界协作,并由他人独立验证。 |
|
|
141
|
+
| [`next`](./skills/next/SKILL.md) | 按优先级建议接下来的待办——未收尾的工作、已破坏或未兑现的承诺——会话已有工作时基于本次会话,仅当会话为空时才基于代码树;命令后的文字说明问什么、路径说明看哪里。只读,输出带证据和启动命令的简短编号清单。 |
|
|
139
142
|
|
|
140
143
|
### 主题
|
|
141
144
|
|
|
@@ -157,6 +160,10 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
157
160
|
<td width="50%"><img src="assets/job.png" alt="/jobs 屏幕:摘要行、带状态字形和耗时的任务行,以及焦点任务的命令、工作目录和最后一行输出" width="100%"></td>
|
|
158
161
|
<td width="50%"><img src="assets/rewind.png" alt="/rewind 屏幕:从新到旧的提示行、标记有代码快照的菱形,以及焦点提示的快照详情" width="100%"></td>
|
|
159
162
|
</tr>
|
|
163
|
+
<tr>
|
|
164
|
+
<td width="50%"><img src="assets/session.png" alt="/sessions 屏幕:计数摘要、带未读数和路径声明数的会话行、焦点会话的工作目录、声明和身份,以及 Tab 范围与监视提示" width="100%"></td>
|
|
165
|
+
<td width="50%"><img src="assets/watch.png" alt="/watch 屏幕:摘要行和带实时匹配数的监视行,以及焦点监视的模式与来源" width="100%"></td>
|
|
166
|
+
</tr>
|
|
160
167
|
</table>
|
|
161
168
|
|
|
162
169
|
### 工具渲染
|
|
@@ -166,7 +173,7 @@ changelog。新版本还会标在头部 —— 本包的与 Pi 自己的。不
|
|
|
166
173
|
(每个工具自身的渲染器或 bytefly 的通用回退)——用户铭牌与通知、Pi 内置工具,以及本包注册的每个工具。
|
|
167
174
|
侧栏字形由 `chrome.rail` 设置。
|
|
168
175
|
|
|
169
|
-

|
|
176
|
+

|
|
170
177
|
|
|
171
178
|
`bun run screenshot:tools` 重新生成它;`bun run screenshot:tool-pngs` 在
|
|
172
179
|
[`assets/tools/`](./assets/tools) 下为每个工具输出一张图。
|
|
@@ -327,7 +327,7 @@ See [The control center](#the-control-center).
|
|
|
327
327
|
**Notify.** Off by default, one `notify` section in `bytefly.json` turns on OS
|
|
328
328
|
notifications for unattended runs: when a full agent run settles, when a
|
|
329
329
|
background job finishes, when the agent opens a prompt asking for input, and when
|
|
330
|
-
|
|
330
|
+
an armed `watch` wake match fires as the agent becomes idle. The
|
|
331
331
|
method follows the terminal (OSC 777, OSC 99, a Windows toast) or falls back to
|
|
332
332
|
the platform notifier (`osascript`, `notify-send`); see
|
|
333
333
|
[Notifications](#notifications).
|
|
@@ -674,6 +674,12 @@ it. There is nothing to probe, so `r` is not offered here; the metadata is read
|
|
|
674
674
|
once when the section first appears, so an edited `SKILL.md` shows on the next
|
|
675
675
|
open.
|
|
676
676
|
|
|
677
|
+
Themes and prompts have no section of their own, by decision rather than by
|
|
678
|
+
omission: a theme is one active selection — a scalar, global setting — and a
|
|
679
|
+
prompt template is a file Pi discovers from a directory, so neither is a scoped
|
|
680
|
+
enable list this screen's checkbox rows can write. Themes stay with `pi config`;
|
|
681
|
+
`ROADMAP.md` carries the reason under *Deliberately left thin*.
|
|
682
|
+
|
|
677
683
|
**Settings.** The third section uses the same frame and the same `Tab` scope
|
|
678
684
|
switch, with its own cursor. It is the shortlist a session changes: thirteen
|
|
679
685
|
preferences on one flat line each, the value beside its label, and no group
|
|
@@ -692,7 +698,6 @@ Bytefly ────────────────────────
|
|
|
692
698
|
◼ Job finished On
|
|
693
699
|
◼ Watcher matched On
|
|
694
700
|
◻ Wake when a job finishes Off
|
|
695
|
-
◼ Offer the session goal On
|
|
696
701
|
◼ Automatic snapshots On
|
|
697
702
|
◼ Proactive health check On
|
|
698
703
|
Currency CNY (¥)
|
|
@@ -718,7 +723,6 @@ Bytefly ────────────────────────
|
|
|
718
723
|
| Job finished | `notify.jobFinished` | Off, On |
|
|
719
724
|
| Watcher matched | `notify.matchFound` | Off, On |
|
|
720
725
|
| Wake when a job finishes | `job.wakeOnFinish` | Off, On |
|
|
721
|
-
| Offer the session goal | `plan.goalPrompt` | Off, On |
|
|
722
726
|
| Automatic snapshots | `rewind.autoSnapshots` | Off, On |
|
|
723
727
|
| Proactive health check | `doctor.proactive` | Off, On |
|
|
724
728
|
| Currency | `price.currency.code` | CNY, USD |
|
|
@@ -756,15 +760,15 @@ terminal: adding a setting means removing one (`panel/panel.test.ts` holds the
|
|
|
756
760
|
ceiling). Everything else stays in `bytefly.json` — the tuning numbers, the
|
|
757
761
|
cosmetic labels, and the Pi preferences Pi's own `/settings` owns — and
|
|
758
762
|
`test/settings-coverage.test.ts` keeps the split honest: every loader key is
|
|
759
|
-
either a row or a declared JSON-only edit with the reason it left.
|
|
760
|
-
`bytefly.json` sections therefore have no row at all (`chrome`, `goal`, `
|
|
761
|
-
`worktree`, `memory`), as do `notify.title`, `doctor.timeoutMs`,
|
|
763
|
+
either a row or a declared JSON-only edit with the reason it left. Six
|
|
764
|
+
`bytefly.json` sections therefore have no row at all (`chrome`, `goal`, `plan`,
|
|
765
|
+
`watch`, `worktree`, `memory`), as do `notify.title`, `doctor.timeoutMs`,
|
|
762
766
|
`price.currency.decimals`, `rewind.max`, `rewind.safetySnapshot`,
|
|
763
767
|
`job.detachedByDefault`, and `watch.wakeOnMatch` inside sections that do. Each is
|
|
764
768
|
documented in [`docs/configuration.md`](../../docs/configuration.md).
|
|
765
769
|
|
|
766
|
-
|
|
767
|
-
|
|
770
|
+
Two of the five sections belong to other extensions (`rewind` and `job`). The
|
|
771
|
+
screen cannot import their normalizers, so it reports the leaf as
|
|
768
772
|
the file states it and declares the loader's default; the same test holds the
|
|
769
773
|
catalogue to every loader's defaults and bounds in both directions.
|
|
770
774
|
|
|
@@ -788,16 +792,19 @@ The non-`tui` form prints the headline and one `Label: Value` row per line, in
|
|
|
788
792
|
screen order:
|
|
789
793
|
|
|
790
794
|
```
|
|
791
|
-
bytefly: Settings · Global ·
|
|
795
|
+
bytefly: Settings · Global · 13 settings
|
|
792
796
|
Bytefly startup TUI: Off
|
|
793
|
-
Theme:
|
|
794
|
-
Desktop notifications:
|
|
797
|
+
Theme: bytefly-dark
|
|
798
|
+
Desktop notifications: On
|
|
795
799
|
Turn finished: On
|
|
796
800
|
Needs input: On
|
|
797
801
|
Job finished: On
|
|
798
802
|
Watcher matched: On
|
|
799
|
-
|
|
800
|
-
|
|
803
|
+
Wake when a job finishes: On
|
|
804
|
+
Automatic snapshots: On
|
|
805
|
+
Proactive health check: On
|
|
806
|
+
Currency: CNY (¥)
|
|
807
|
+
Session budget: 5
|
|
801
808
|
```
|
|
802
809
|
|
|
803
810
|
The doctor side probes every declared extension and reports each check as `ok`,
|
|
@@ -860,7 +867,7 @@ has a keyboard path.
|
|
|
860
867
|
| rewind | `git` | — |
|
|
861
868
|
| document | — | — |
|
|
862
869
|
| subagent | a runnable nested `pi` | project-local agents need a trusted project |
|
|
863
|
-
| plan | — |
|
|
870
|
+
| plan | — | an interactive UI |
|
|
864
871
|
| memory | — | `git` for the project-scope root |
|
|
865
872
|
| file-browse | — | `git` for the branch chip; the browser opener is best-effort |
|
|
866
873
|
| web-access | — | `unpdf` |
|
|
@@ -892,12 +899,12 @@ of `bytefly.json` (see [Configuration](#configuration)):
|
|
|
892
899
|
- **A background job finished.** The [job](../job/) extension announces each
|
|
893
900
|
terminal transition on the shared `pi.events` bus
|
|
894
901
|
(`my-pi-agent/job-finished`); bytefly listens and never imports it.
|
|
895
|
-
- **A watcher matched.** A [watch](../watch/) whose `wake` is on matched
|
|
896
|
-
|
|
902
|
+
- **A watcher matched.** A [watch](../watch/) whose `wake` is on matched, and
|
|
903
|
+
announced it on `my-pi-agent/watch-match` with the cycle's
|
|
897
904
|
count, the watcher, and its newest line. The body names that line, sanitized and
|
|
898
905
|
clipped to 80 characters, because the line is the alert: a watch usually tails a
|
|
899
|
-
build or an error log. A match the agent was busy for
|
|
900
|
-
|
|
906
|
+
build or an error log. A match the agent was busy for notifies once that run
|
|
907
|
+
settles, when its wake is raised.
|
|
901
908
|
|
|
902
909
|
### Delivery method
|
|
903
910
|
|
|
@@ -21,7 +21,7 @@ export interface NotifyConfig {
|
|
|
21
21
|
needsInput: boolean;
|
|
22
22
|
/** Notify when a background `job` finishes. */
|
|
23
23
|
jobFinished: boolean;
|
|
24
|
-
/** Notify when a `watch` wake match fires
|
|
24
|
+
/** Notify when a `watch` wake match fires, once the agent is idle. */
|
|
25
25
|
matchFound: boolean;
|
|
26
26
|
/** Delivery method; `auto` chooses by terminal and platform. */
|
|
27
27
|
method: NotifyMethod;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* The catalogue is the shortlist a session changes, not the whole document: every
|
|
10
10
|
* row is one a workflow differs on, and each states its own rule so a value the
|
|
11
11
|
* screen accepts is a value the loader keeps. The catalogue order is the screen's
|
|
12
|
-
* order, and it is capped so the section fits a 24-row terminal (`
|
|
12
|
+
* order, and it is capped so the section fits a 24-row terminal (`panel.test.ts`
|
|
13
13
|
* holds the ceiling); a new row has to displace one. Everything else stays
|
|
14
14
|
* `bytefly.json` — a list (`doctor.skip`), a table (`price.rates`), a schedule
|
|
15
15
|
* (`price.peak`), and the tuning numbers and labels this screen deliberately does
|
|
@@ -17,14 +17,15 @@
|
|
|
17
17
|
* pane of any row whose section is still on the list.
|
|
18
18
|
*
|
|
19
19
|
* Three sections have a normalizer here, so the screen shows what the notifier,
|
|
20
|
-
* the doctor, and the footer keep. The
|
|
21
|
-
* `job
|
|
20
|
+
* the doctor, and the footer keep. The two owned by other extensions (`rewind`
|
|
21
|
+
* and `job`) are read as the file states them, because importing their
|
|
22
22
|
* normalizer would be one extension importing another's module; each such row
|
|
23
23
|
* declares the loader's default, and `test/settings-coverage.test.ts` holds the
|
|
24
24
|
* pair together.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { configSection, configValueAt } from "../../../lib/config.ts";
|
|
28
|
+
import { SPLIT_KEY, SPLIT_SECTION, SPLIT_SETTING_ID, SPLIT_SETTING_LABEL } from "../../../lib/plans/setting.ts";
|
|
28
29
|
import { DEFAULT_CONFIG as DEFAULT_DOCTOR_CONFIG, normalizeConfig as normalizeDoctorConfig } from "../doctor/config.ts";
|
|
29
30
|
import {
|
|
30
31
|
CURRENCY_DEFAULTS,
|
|
@@ -38,7 +39,7 @@ import { DEFAULT_NOTIFY_CONFIG, normalizeNotifyConfig } from "../notify/config.t
|
|
|
38
39
|
import type { Settings, WriteScope } from "../picker/types.ts";
|
|
39
40
|
|
|
40
41
|
/** Where a preference is stored. */
|
|
41
|
-
type SettingSource = "app" | "bytefly";
|
|
42
|
+
type SettingSource = "app" | "bytefly" | "plan";
|
|
42
43
|
|
|
43
44
|
/** The row control a preference uses. */
|
|
44
45
|
type SettingKind = "boolean" | "enum" | "text";
|
|
@@ -220,7 +221,7 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
220
221
|
{
|
|
221
222
|
id: "notify.matchFound",
|
|
222
223
|
label: "Watcher matched",
|
|
223
|
-
description: "Announce it when a `watch` whose `wake` is on matches
|
|
224
|
+
description: "Announce it when a `watch` whose `wake` is on matches, once the agent is idle.",
|
|
224
225
|
source: "bytefly",
|
|
225
226
|
kind: "boolean",
|
|
226
227
|
fallback: "true",
|
|
@@ -239,17 +240,6 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
239
240
|
options: ON_OFF,
|
|
240
241
|
config: { section: "job", path: ["wakeOnFinish"] },
|
|
241
242
|
},
|
|
242
|
-
{
|
|
243
|
-
id: "plan.goalPrompt",
|
|
244
|
-
label: "Offer the session goal",
|
|
245
|
-
description: "Ask before recording an approved plan as the session goal; off records it without asking.",
|
|
246
|
-
source: "bytefly",
|
|
247
|
-
kind: "boolean",
|
|
248
|
-
fallback: "true",
|
|
249
|
-
json: "boolean",
|
|
250
|
-
options: ON_OFF,
|
|
251
|
-
config: { section: "plan", path: ["goalPrompt"] },
|
|
252
|
-
},
|
|
253
243
|
{
|
|
254
244
|
id: "rewind.autoSnapshots",
|
|
255
245
|
label: "Automatic snapshots",
|
|
@@ -306,14 +296,31 @@ export const SETTING_ROWS: readonly SettingDescriptor[] = [
|
|
|
306
296
|
text: amountRule(0, MAX_BUDGET),
|
|
307
297
|
config: { section: "price", path: ["budget"] },
|
|
308
298
|
},
|
|
299
|
+
{
|
|
300
|
+
// The split's switch, with the label, id, and default taken from the module
|
|
301
|
+
// that reads it, so this row cannot describe a key nothing honours.
|
|
302
|
+
id: SPLIT_SETTING_ID,
|
|
303
|
+
label: SPLIT_SETTING_LABEL,
|
|
304
|
+
description:
|
|
305
|
+
"Let an approved plan carry a team of slices, which separate sessions join by name. Off keeps every plan one flow.",
|
|
306
|
+
source: "plan",
|
|
307
|
+
kind: "boolean",
|
|
308
|
+
fallback: "false",
|
|
309
|
+
json: "boolean",
|
|
310
|
+
options: ON_OFF,
|
|
311
|
+
config: { section: SPLIT_SECTION, path: [SPLIT_KEY] },
|
|
312
|
+
},
|
|
309
313
|
];
|
|
310
314
|
|
|
311
315
|
/** The one refusal for a Project write while the project is untrusted. */
|
|
312
316
|
export const UNTRUSTED_SETTINGS_NOTE = "Project is not trusted; settings can only be changed in Global scope.";
|
|
313
317
|
|
|
314
|
-
/**
|
|
318
|
+
/**
|
|
319
|
+
* The rows a scope can write: app rows are personal-file only, and Project shows
|
|
320
|
+
* the rows backed by `bytefly.json` — whichever extension owns the section.
|
|
321
|
+
*/
|
|
315
322
|
export function rowsForScope(scope: WriteScope): readonly SettingDescriptor[] {
|
|
316
|
-
return scope === "global" ? SETTING_ROWS : SETTING_ROWS.filter((row) => row.
|
|
323
|
+
return scope === "global" ? SETTING_ROWS : SETTING_ROWS.filter((row) => row.config !== undefined);
|
|
317
324
|
}
|
|
318
325
|
|
|
319
326
|
/**
|
|
@@ -56,8 +56,9 @@ pi -e . # load the whole @gavin-hu/my-pi-agen
|
|
|
56
56
|
external images are shown as links rather than fetched.
|
|
57
57
|
- **Sortable listings.** The Name / Size / Modified headers sort the current
|
|
58
58
|
directory, directories first, and the choice is remembered per browser.
|
|
59
|
-
- **Copy and wrap.** Copy a file's root-relative path or its contents,
|
|
60
|
-
|
|
59
|
+
- **Copy and wrap.** Copy a file's root-relative path or its contents, copy a
|
|
60
|
+
`path:12-30` reference for the lines you selected, and toggle line wrapping for
|
|
61
|
+
text and raw views.
|
|
61
62
|
- **Theme toggle.** A header button switches between the dark and light
|
|
62
63
|
palettes and remembers the choice per browser; until it is used, the palette
|
|
63
64
|
follows the system `prefers-color-scheme`.
|
|
@@ -66,7 +67,8 @@ pi -e . # load the whole @gavin-hu/my-pi-agen
|
|
|
66
67
|
highlighted match; Enter opens the file.
|
|
67
68
|
- **Keyboard.** `/` or `Ctrl/Cmd+K` opens quick open, `-` folds or expands
|
|
68
69
|
every folder in the tree, `u` toggles line wrapping, `r` switches rendered and
|
|
69
|
-
raw Markdown, `
|
|
70
|
+
raw Markdown, `y` copies a reference to the selected lines, `n`/`p` step
|
|
71
|
+
between a diff's hunks, and `?` opens a shortcut
|
|
70
72
|
sheet. A diff's hunk headers pin to the top of the code viewport while its
|
|
71
73
|
body scrolls.
|
|
72
74
|
- **Read-only and loopback-scoped.** No editing, no writing, no LAN exposure.
|
|
@@ -88,11 +90,13 @@ pi -e . # load the whole @gavin-hu/my-pi-agen
|
|
|
88
90
|
connecting (accent), stalled (amber, after three missed frames), or offline
|
|
89
91
|
(red); the branch chip, the `● N changes +A −D` chip, and the change markers in
|
|
90
92
|
the tree and the listing update in place; and the footer line reports `up 2m
|
|
91
|
-
14s · 37 requests`. The chip names its state and never counts,
|
|
92
|
-
|
|
93
|
-
the same loopback server, so nothing extra is
|
|
94
|
-
that stream is also how the server notices the
|
|
95
|
-
after which it stops listening.
|
|
93
|
+
14s · 37 requests`. The chip names its state and never counts, and a frame
|
|
94
|
+
whose change set did not move repaints nothing at all. One Server-Sent Events
|
|
95
|
+
stream per page carries it, on the same loopback server, so nothing extra is
|
|
96
|
+
opened and nothing is written; that stream is also how the server notices the
|
|
97
|
+
last page closing its window, after which it stops listening. A page that lists
|
|
98
|
+
a folder also checks that folder, and offers a `⟳ reload` control when a file
|
|
99
|
+
has appeared or gone on disk since it drew its rows.
|
|
96
100
|
- **No dependencies.** `node:http` plus the inline sprite, CSS, and client
|
|
97
101
|
script.
|
|
98
102
|
|
|
@@ -136,10 +140,24 @@ errors. The chip names its state rather than counting, so it is repainted only
|
|
|
136
140
|
when that state changes. The same frame carries the branch (or detached head), the
|
|
137
141
|
uncommitted-change totals and paths, the server's uptime, and the requests it
|
|
138
142
|
has answered, so the branch chip, the changes chip, the markers, and the footer
|
|
139
|
-
line are painted from one snapshot rather than four requests.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
+
line are painted from one snapshot rather than four requests. Each change set
|
|
144
|
+
also carries a short revision, and a frame whose revision the page already
|
|
145
|
+
painted does no work at all — so an idle tree costs no DOM, however many rows the
|
|
146
|
+
page drew. Losing the stream leaves everything the page last showed in place: it
|
|
147
|
+
is read-only, so a stale label is never a stale action. `"live": false` turns the
|
|
148
|
+
whole surface off — no chip, no stream, no `/events` route — and so does
|
|
149
|
+
JavaScript off.
|
|
150
|
+
|
|
151
|
+
A page that lists a folder carries the revision of the names it drew, and asks
|
|
152
|
+
`/api/dir-rev` for the folder's current one on the frame cadence — one directory
|
|
153
|
+
read every five seconds by default, skipped while the tab is hidden and stopped
|
|
154
|
+
for good once it has an answer. A difference reveals `⟳ reload` beside the live
|
|
155
|
+
chip, which reloads the page; the rows themselves are never touched, because a
|
|
156
|
+
page that could grow a row is a page that writes. A folder whose listing was
|
|
157
|
+
truncated, and a file, `/diff`, or error page, has nothing to compare and shows
|
|
158
|
+
no control. At most eight pages may hold the stream at once: a ninth is refused
|
|
159
|
+
and its chip reads `offline`, which keeps one local page from pinning the server
|
|
160
|
+
— and the git read behind each frame — alive.
|
|
143
161
|
|
|
144
162
|
The stream is also how the server knows a page is still there: when the last one
|
|
145
163
|
leaves, the port is released after ten seconds and the chip is cleared, because
|
|
@@ -212,7 +230,7 @@ document and the project document (project wins):
|
|
|
212
230
|
"diffContext": 3, // unified diff context lines
|
|
213
231
|
"maxDiffLines": 4000, // diff lines rendered before truncation
|
|
214
232
|
"live": true, // stream live status to open pages
|
|
215
|
-
"liveIntervalMs":
|
|
233
|
+
"liveIntervalMs": 5000 // ms between status frames while a page is connected
|
|
216
234
|
}
|
|
217
235
|
```
|
|
218
236
|
|
|
@@ -249,11 +267,18 @@ document and the project document (project wins):
|
|
|
249
267
|
attributes; only the fixed `tok-*` class names reach the page.
|
|
250
268
|
- **Event stream.** `/events` is a `GET` on the same loopback server, behind
|
|
251
269
|
the same method and `Host` checks, and it only reads: the frame is the branch,
|
|
252
|
-
the change paths, an uptime, and a request count, all of
|
|
253
|
-
feeds already renders. It carries no page policy
|
|
254
|
-
document), sends `Cache-Control: no-store`, and
|
|
255
|
-
A tick runs only while a page is attached, and
|
|
256
|
-
idle server does no work and a forgotten tab
|
|
270
|
+
the change paths and their revision, an uptime, and a request count, all of
|
|
271
|
+
which the page it feeds already renders. It carries no page policy
|
|
272
|
+
(`text/event-stream` is not a document), sends `Cache-Control: no-store`, and
|
|
273
|
+
cannot be cached or replayed. A tick runs only while a page is attached, and
|
|
274
|
+
the timer is `unref`ed, so an idle server does no work and a forgotten tab
|
|
275
|
+
cannot hold the process open. At most eight pages may attach; a ninth is
|
|
276
|
+
answered `204`, the one status an event source never reconnects after.
|
|
277
|
+
- **Directory check.** `/api/dir-rev` answers one folder's listing revision, so
|
|
278
|
+
the page can tell whether its rows are stale. It goes through the same path
|
|
279
|
+
guard as every other route and reads one directory; its answer is a hash of the
|
|
280
|
+
names, not the names themselves, so it discloses nothing the page above it does
|
|
281
|
+
not already show.
|
|
257
282
|
- **Caps.** `maxFileBytes` (inline rendering), `maxTextLines` (rendered lines),
|
|
258
283
|
`maxThumbBytes` (thumbnails), and `maxDirEntries` (listings) bound every read.
|
|
259
284
|
- **Git reads.** The header chip and the diff view run read-only git
|
|
@@ -271,9 +296,11 @@ document and the project document (project wins):
|
|
|
271
296
|
approximated rather than parsed.
|
|
272
297
|
- Live status updates what the page already contains: the header chips, the
|
|
273
298
|
markers on the rows it rendered, and the footer line. A file that appears on
|
|
274
|
-
disk
|
|
275
|
-
|
|
276
|
-
|
|
299
|
+
disk does not join the listing by itself — the page offers `⟳ reload` instead —
|
|
300
|
+
and the check covers the folder the page lists, by name, not the folders inside
|
|
301
|
+
it, a listed file's contents, the `/diff` table, or a file page's `changes`
|
|
302
|
+
action, which stay page-load snapshots. The branch chip is only patched when
|
|
303
|
+
the page was served inside a repository.
|
|
277
304
|
- `/browse` has no auth; a malicious local page could probe the port. The `Host`
|
|
278
305
|
allowlist and the absence of CORS headers mitigate reads, and the server is
|
|
279
306
|
read-only.
|
|
@@ -314,6 +341,18 @@ document and the project document (project wins):
|
|
|
314
341
|
method and `Host`, parses the URL, matches a route, and runs every path
|
|
315
342
|
through `paths.ts`. It returns a plain `ServeResponse`, so routing is tested
|
|
316
343
|
without a socket; `server.ts` is the only part that binds a port.
|
|
344
|
+
- **One snapshot, one frame.** The status source is shared by every attached
|
|
345
|
+
page, so a tick costs one `git status`, one `git diff --stat`, and one
|
|
346
|
+
serialization however many tabs are open. The frame carries a revision of the
|
|
347
|
+
change set, and the client compares it before painting, which is why an idle
|
|
348
|
+
page does no DOM work. The cadence is what bounds those reads, so the default
|
|
349
|
+
is five seconds rather than matching the providers' two-second render cache.
|
|
350
|
+
- **A poll, not a watcher.** The folder check is one request from the page to
|
|
351
|
+
`/api/dir-rev`, not an `fs.watch`: recursive watching is the one part of
|
|
352
|
+
`node:fs` whose availability and event semantics differ per platform, and it
|
|
353
|
+
would add a long-lived resource to start and release around `close()`. The
|
|
354
|
+
check compares names, so it is a directory read rather than a stat pass, and it
|
|
355
|
+
stops at the first difference because the control, not the checker, is the fix.
|
|
317
356
|
- **Progressive UI.** The page is server-rendered HTML with an inline style
|
|
318
357
|
block and inline SVG icons. `client.ts` enhances it: the filter hides
|
|
319
358
|
non-matching rows while keeping ancestors, disclosure triangles lazily
|