@gavin-hu/my-pi-agent 0.21.0 → 0.22.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.
Files changed (254) hide show
  1. package/README.md +46 -31
  2. package/README.zh-CN.md +40 -26
  3. package/assets/screens/board.png +0 -0
  4. package/assets/screens/chrome.png +0 -0
  5. package/assets/screens/file-browse.png +0 -0
  6. package/assets/screens/plan-review.png +0 -0
  7. package/assets/screens/plan.png +0 -0
  8. package/docs/extensions/README.md +22 -24
  9. package/docs/extensions/board.md +361 -147
  10. package/docs/extensions/bytefly.md +152 -111
  11. package/docs/extensions/check.md +15 -17
  12. package/docs/extensions/context.md +35 -15
  13. package/docs/extensions/file-browse.md +30 -31
  14. package/docs/extensions/file-open.md +9 -11
  15. package/docs/extensions/file-read.md +12 -14
  16. package/docs/extensions/goal.md +15 -17
  17. package/docs/extensions/job.md +54 -42
  18. package/docs/extensions/memory.md +17 -19
  19. package/docs/extensions/plan.md +166 -126
  20. package/docs/extensions/question.md +16 -18
  21. package/docs/extensions/rewind.md +17 -19
  22. package/docs/extensions/serve.md +34 -18
  23. package/docs/extensions/session-bus.md +38 -16
  24. package/docs/extensions/subagent.md +23 -25
  25. package/docs/extensions/team.md +72 -33
  26. package/docs/extensions/todo.md +18 -18
  27. package/docs/extensions/watch.md +31 -31
  28. package/docs/extensions/web-access.md +2 -4
  29. package/docs/extensions/wechat.md +34 -35
  30. package/docs/extensions/worktree.md +56 -50
  31. package/extensions/board/commands.ts +56 -15
  32. package/extensions/board/format.ts +43 -24
  33. package/extensions/board/index.ts +5 -4
  34. package/extensions/board/input.ts +4 -9
  35. package/extensions/board/join.ts +4 -40
  36. package/extensions/board/lazy-page.ts +40 -0
  37. package/extensions/board/page.ts +13 -11
  38. package/extensions/board/result.ts +30 -16
  39. package/extensions/board/rows.ts +62 -25
  40. package/extensions/board/schema.ts +42 -10
  41. package/extensions/board/snapshot.ts +2 -1
  42. package/extensions/board/tone.ts +22 -0
  43. package/extensions/board/tools.ts +131 -44
  44. package/extensions/board/types.ts +36 -32
  45. package/extensions/board/view/card.ts +229 -0
  46. package/extensions/board/view/client.ts +33 -15
  47. package/extensions/board/view/dialog.ts +169 -6
  48. package/extensions/board/view/empty.ts +47 -0
  49. package/extensions/board/view/keys.ts +13 -2
  50. package/extensions/board/view/live.ts +89 -21
  51. package/extensions/board/view/names.ts +13 -4
  52. package/extensions/board/view/page.ts +23 -9
  53. package/extensions/board/view/render.ts +208 -271
  54. package/extensions/board/view/styles.ts +123 -31
  55. package/extensions/board/view/team.ts +297 -76
  56. package/extensions/bytefly/block/fallback.ts +1 -1
  57. package/extensions/bytefly/doctor/runtime.ts +5 -2
  58. package/extensions/bytefly/footer/collect/label.ts +60 -0
  59. package/extensions/bytefly/footer/collect/snapshot.ts +8 -1
  60. package/extensions/bytefly/footer/config.ts +4 -2
  61. package/extensions/bytefly/footer/register.ts +33 -4
  62. package/extensions/bytefly/footer/render/lines.ts +7 -4
  63. package/extensions/bytefly/footer/render/segments.ts +37 -10
  64. package/extensions/bytefly/footer/render/status.ts +0 -11
  65. package/extensions/bytefly/footer/types.ts +7 -0
  66. package/extensions/bytefly/header/config.ts +1 -1
  67. package/extensions/bytefly/index.ts +32 -6
  68. package/extensions/bytefly/mode/editor.ts +115 -0
  69. package/extensions/bytefly/panel/commands.ts +210 -120
  70. package/extensions/bytefly/panel/format.ts +4 -4
  71. package/extensions/bytefly/panel/settings.ts +73 -6
  72. package/extensions/bytefly/panel/tui/keys.ts +2 -6
  73. package/extensions/bytefly/update/cache.ts +1 -1
  74. package/extensions/bytefly/update/register.ts +4 -4
  75. package/extensions/bytefly/working/config.ts +5 -7
  76. package/extensions/bytefly/working/format.ts +10 -13
  77. package/extensions/bytefly/working/register.ts +22 -27
  78. package/extensions/check/commands.ts +3 -2
  79. package/extensions/check/{tui.ts → view/check-screens.ts} +14 -19
  80. package/extensions/context/commands.ts +2 -2
  81. package/extensions/context/{tui.ts → view/context-report.ts} +51 -19
  82. package/extensions/file-browse/index.ts +67 -36
  83. package/extensions/file-read/render.ts +4 -4
  84. package/extensions/goal/plan-route.ts +2 -2
  85. package/extensions/job/child.ts +527 -0
  86. package/extensions/job/clock.ts +142 -0
  87. package/extensions/job/commands.ts +4 -2
  88. package/extensions/job/config.ts +8 -1
  89. package/extensions/job/format.ts +22 -1
  90. package/extensions/job/log-writer.ts +13 -2
  91. package/extensions/job/registry.ts +63 -7
  92. package/extensions/job/render.ts +34 -0
  93. package/extensions/job/runtime.ts +296 -655
  94. package/extensions/job/session.ts +132 -19
  95. package/extensions/job/store.ts +7 -7
  96. package/extensions/job/tools.ts +3 -3
  97. package/extensions/job/types.ts +47 -0
  98. package/extensions/job/{tui.ts → view/jobs-screen.ts} +19 -73
  99. package/extensions/job/waiters.ts +44 -1
  100. package/extensions/memory/commands.ts +4 -2
  101. package/extensions/memory/{tui.ts → view/memory-picker.ts} +12 -12
  102. package/extensions/plan/commands.ts +12 -9
  103. package/extensions/plan/format.ts +8 -2
  104. package/extensions/plan/git-bash.ts +115 -16
  105. package/extensions/plan/index.ts +53 -52
  106. package/extensions/plan/plan-index.ts +4 -2
  107. package/extensions/plan/plans.ts +5 -54
  108. package/extensions/plan/policy.ts +8 -10
  109. package/extensions/plan/review-lazy.ts +85 -0
  110. package/extensions/plan/review.ts +2 -2
  111. package/extensions/plan/runtime.ts +49 -39
  112. package/extensions/plan/sections.ts +1 -1
  113. package/extensions/plan/steps.ts +3 -3
  114. package/extensions/plan/todos.ts +1 -1
  115. package/extensions/plan/tools/cancel.ts +27 -62
  116. package/extensions/plan/tools/enter.ts +55 -81
  117. package/extensions/plan/tools/exit.ts +221 -238
  118. package/extensions/plan/tools/refusal.ts +18 -0
  119. package/extensions/plan/tools/steps.ts +75 -92
  120. package/extensions/plan/tools/write.ts +77 -120
  121. package/extensions/plan/tools.ts +188 -30
  122. package/extensions/plan/tui.ts +5 -5
  123. package/extensions/plan/types.ts +48 -5
  124. package/extensions/plan/web-client.ts +3 -0
  125. package/extensions/plan/web-lazy.ts +53 -0
  126. package/extensions/plan/web-markdown.ts +9 -67
  127. package/extensions/plan/web-payload.ts +3 -3
  128. package/extensions/plan/web-router.ts +18 -9
  129. package/extensions/plan/web.ts +1 -12
  130. package/extensions/question/tools.ts +6 -2
  131. package/extensions/question/{tui.ts → view/question-screen.ts} +11 -11
  132. package/extensions/rewind/commands/commands.ts +6 -3
  133. package/extensions/rewind/state/runtime.ts +1 -1
  134. package/extensions/rewind/{view/status.ts → status.ts} +4 -4
  135. package/extensions/rewind/view/review-tui.ts +4 -4
  136. package/extensions/serve/config.ts +10 -8
  137. package/extensions/serve/index.ts +17 -3
  138. package/extensions/serve/registry.ts +26 -17
  139. package/extensions/session-bus/commands.ts +11 -6
  140. package/extensions/session-bus/join-request.ts +2 -1
  141. package/extensions/session-bus/mail-watch.ts +26 -17
  142. package/extensions/session-bus/protocol.ts +15 -3
  143. package/extensions/session-bus/resolve.ts +5 -7
  144. package/extensions/session-bus/runtime.ts +40 -12
  145. package/extensions/session-bus/store.ts +101 -19
  146. package/extensions/session-bus/types.ts +19 -0
  147. package/extensions/session-bus/{tui.ts → view/session-list.ts} +16 -16
  148. package/extensions/subagent/agents.ts +1 -1
  149. package/extensions/subagent/commands.ts +4 -2
  150. package/extensions/subagent/format.ts +15 -15
  151. package/extensions/subagent/index.ts +1 -1
  152. package/extensions/subagent/render.ts +3 -3
  153. package/extensions/subagent/{background-tui.ts → view/agents-board.ts} +11 -11
  154. package/extensions/team/commands.ts +24 -7
  155. package/extensions/team/dispatch.ts +18 -4
  156. package/extensions/team/format.ts +17 -2
  157. package/extensions/team/index.ts +9 -8
  158. package/extensions/team/schema.ts +6 -5
  159. package/extensions/team/tools.ts +107 -45
  160. package/extensions/team/types.ts +3 -2
  161. package/extensions/todo/commands.ts +4 -2
  162. package/extensions/todo/format.ts +11 -0
  163. package/extensions/todo/render.ts +57 -0
  164. package/extensions/todo/runtime.ts +1 -1
  165. package/extensions/todo/tools.ts +1 -1
  166. package/extensions/todo/view/todo-screen.ts +122 -0
  167. package/extensions/todo/widget.ts +47 -0
  168. package/extensions/watch/commands.ts +4 -2
  169. package/extensions/watch/format.ts +36 -7
  170. package/extensions/watch/render.ts +57 -0
  171. package/extensions/watch/runtime.ts +27 -22
  172. package/extensions/watch/tools.ts +4 -4
  173. package/extensions/watch/{tui.ts → view/watch-screen.ts} +18 -80
  174. package/extensions/web-access/fetch/tool.ts +12 -4
  175. package/extensions/wechat/commands/commands.ts +18 -14
  176. package/extensions/wechat/index.ts +72 -37
  177. package/extensions/wechat/state/credentials.ts +1 -1
  178. package/extensions/wechat/state/state.ts +1 -1
  179. package/extensions/wechat/text/status.ts +112 -0
  180. package/extensions/wechat/types.ts +2 -2
  181. package/extensions/wechat/view/status-screen.ts +4 -103
  182. package/extensions/worktree/commands.ts +11 -9
  183. package/extensions/worktree/enter.ts +2 -2
  184. package/extensions/worktree/exit.ts +2 -2
  185. package/extensions/worktree/index.ts +5 -5
  186. package/extensions/worktree/screen.ts +3 -3
  187. package/extensions/worktree/status.ts +2 -2
  188. package/extensions/worktree/tools.ts +113 -116
  189. package/lib/README.md +27 -13
  190. package/lib/board/actions.ts +111 -0
  191. package/lib/board/artifact.ts +149 -0
  192. package/lib/board/card.ts +163 -52
  193. package/lib/board/config.ts +58 -0
  194. package/lib/board/contract.ts +113 -0
  195. package/lib/board/join.ts +38 -0
  196. package/lib/board/lanes.ts +182 -0
  197. package/lib/board/lead.ts +130 -0
  198. package/lib/board/limits.ts +78 -0
  199. package/lib/board/links.ts +31 -10
  200. package/lib/board/page-pointer.ts +1 -1
  201. package/lib/board/read.ts +83 -0
  202. package/lib/board/reason.ts +102 -0
  203. package/lib/board/round-text.ts +68 -6
  204. package/lib/board/round.ts +31 -15
  205. package/lib/board/rules.ts +151 -307
  206. package/lib/board/seat.ts +35 -0
  207. package/lib/board/session.ts +136 -54
  208. package/lib/board/skipped.ts +22 -0
  209. package/lib/board/steps.ts +487 -0
  210. package/lib/board/store.ts +87 -30
  211. package/lib/board/tone.ts +92 -0
  212. package/lib/board/view.ts +70 -58
  213. package/{extensions/watch → lib}/child.ts +40 -21
  214. package/lib/env.ts +65 -7
  215. package/lib/format.ts +13 -0
  216. package/lib/http/index.ts +14 -12
  217. package/lib/http/port.ts +15 -10
  218. package/lib/lazy.ts +45 -0
  219. package/lib/plan-entry.ts +39 -10
  220. package/lib/plans/paths.ts +82 -0
  221. package/lib/policy.ts +9 -6
  222. package/lib/report.ts +3 -2
  223. package/lib/requirements.ts +8 -8
  224. package/lib/session-label.ts +111 -5
  225. package/lib/session-roster.ts +43 -1
  226. package/lib/session-tool.ts +5 -4
  227. package/lib/stray-fields.ts +7 -2
  228. package/lib/tool-names.ts +5 -10
  229. package/lib/tui/README.md +23 -8
  230. package/lib/tui/chrome.ts +16 -15
  231. package/lib/tui/cursor.ts +18 -3
  232. package/lib/tui/glyphs.ts +9 -7
  233. package/lib/tui/tokens.ts +33 -2
  234. package/lib/tui/tool.ts +3 -3
  235. package/lib/web/README.md +21 -0
  236. package/lib/web/components.ts +5 -1
  237. package/lib/web/index.ts +1 -0
  238. package/lib/web/markdown.ts +83 -0
  239. package/lib/web/markup.ts +2 -1
  240. package/lib/web/runtime.ts +9 -10
  241. package/package.json +6 -1
  242. package/skills/init/SKILL.md +5 -5
  243. package/skills/next/SKILL.md +3 -5
  244. package/extensions/board/seat.ts +0 -28
  245. package/extensions/todo/tui.ts +0 -212
  246. package/lib/tui/index.ts +0 -34
  247. package/skills/project-docs/SKILL.md +0 -133
  248. package/skills/project-docs/references/audit.md +0 -131
  249. package/skills/project-docs/references/changelog.md +0 -105
  250. package/skills/project-docs/references/discovery.md +0 -127
  251. package/skills/project-docs/references/readme.md +0 -80
  252. package/skills/project-docs/references/release.md +0 -84
  253. package/skills/project-docs/references/roadmap.md +0 -93
  254. package/skills/project-docs/scripts/state.ts +0 -316
@@ -8,22 +8,20 @@ framework, or CI system.
8
8
 
9
9
  ## Capabilities
10
10
 
11
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
12
-
13
- | Capability | How | What you get | Status |
14
- |---|---|---|---|
15
- | Plan-mode refusal | `/check`, the read-only policy | Plan mode refuses a check because tests still write caches, snapshots, or generated files; approve the plan first. | Shipped |
16
- | Single active run | `run_check`, `/check` | A second run is refused with the corrective action while one process is active, instead of starting a parallel check. | Shipped |
17
- | Supervised run | `/check`, `run_check` | One process per command, with a wall-clock timeout, a bounded log, and `Esc` to cancel the process tree. | Shipped |
18
- | Command detection | a project manifest, `check.command` | The project's test, lint, and typecheck commands are found without configuration, with a shell command override. | Shipped |
19
- | Target selection | `/check` with a target, `run_check.target` | Run `test`, `lint`, `typecheck`, or `all`; `all` is the default. | Shipped |
20
- | Structured failures | `run_check` | The model gets `path`, `line`, `column`, `test`, `message`, and `command` instead of a wall of log text. | Shipped |
21
- | Failure list | `/check` | A navigable list with a detail view for the focused failure, drawn from a source excerpt or the bounded tail. | Shipped |
22
- | Rerun from the list | `r` in the failure list | Rerun the same check after reading a failure; `Enter` opens its detail and `Esc` closes. | Shipped |
23
- | Live run screen | `/check` | A scrolling tail that repaints while the command runs, so a silent compiler still shows progress. | Shipped |
24
- | Capped transcript | `run_check` | One status summary and at most five failure rows, expanded with `ctrl+o` to the model's 20-failure cap. | Shipped |
25
- | Headless report | `/check`, `run_check` | RPC, JSON, and print sessions post the summary plus the failure list, with no screen. | Shipped |
26
- | Honest fallback | `/check`, `run_check` | An unparsed failure names the exit status and the last output lines, never an invented location. | Shipped |
11
+ | Capability | How | What you get |
12
+ |---|---|---|
13
+ | Plan-mode refusal | `/check`, the read-only policy | Plan mode refuses a check because tests still write caches, snapshots, or generated files; approve the plan first. |
14
+ | Single active run | `run_check`, `/check` | A second run is refused with the corrective action while one process is active, instead of starting a parallel check. |
15
+ | Supervised run | `/check`, `run_check` | One process per command, with a wall-clock timeout, a bounded log, and `Esc` to cancel the process tree. |
16
+ | Command detection | a project manifest, `check.command` | The project's test, lint, and typecheck commands are found without configuration, with a shell command override. |
17
+ | Target selection | `/check` with a target, `run_check.target` | Run `test`, `lint`, `typecheck`, or `all`; `all` is the default. |
18
+ | Structured failures | `run_check` | The model gets `path`, `line`, `column`, `test`, `message`, and `command` instead of a wall of log text. |
19
+ | Failure list | `/check` | A navigable list with a detail view for the focused failure, drawn from a source excerpt or the bounded tail. |
20
+ | Rerun from the list | `r` in the failure list | Rerun the same check after reading a failure; `Enter` opens its detail and `Esc` closes. |
21
+ | Live run screen | `/check` | A scrolling tail that repaints while the command runs, so a silent compiler still shows progress. |
22
+ | Capped transcript | `run_check` | One status summary and at most five failure rows, expanded with `ctrl+o` to the model's 20-failure cap. |
23
+ | Headless report | `/check`, `run_check` | RPC, JSON, and print sessions post the summary plus the failure list, with no screen. |
24
+ | Honest fallback | `/check`, `run_check` | An unparsed failure names the exit status and the last output lines, never an invented location. |
27
25
 
28
26
  ## Quickstart
29
27
 
@@ -252,7 +250,7 @@ never turned into an invented location.
252
250
  | `source.ts` | Guarded source excerpt around a failure's `path:line`. |
253
251
  | `runtime.ts` | Planning, sequencing, aggregation, live lines, cancel/shutdown. |
254
252
  | `format.ts` | Summary, failure rows, source-excerpt/detail text, model report. |
255
- | `tui.ts` | `CheckRunComponent` (a live tail) and `CheckResultComponent` (a `DockListScreen` over the failures). |
253
+ | `view/check-screens.ts` | `CheckRunComponent` (a live tail) and `CheckResultComponent` (a `DockListScreen` over the failures), loaded on first use. |
256
254
  | `tools.ts` | `run_check` schema, registration, the running partial result, and the call/result renderers. |
257
255
  | `render.ts` | The transcript result block: status summary, capped failure rows, tail fallback. |
258
256
  | `commands.ts` | `/check`, target parsing, completions, TUI/headless flow. |
@@ -7,20 +7,18 @@ untouched.
7
7
 
8
8
  ## Capabilities
9
9
 
10
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
11
-
12
- | Capability | How | What you get | Status |
13
- |---|---|---|---|
14
- | Window headline | `/context` | Pi's own estimate: tokens, window, percentage, free space, and the auto-compaction threshold with the headroom left before it. | Shipped |
15
- | Composition breakdown | `/context` | Where the window went — system prompt, active tool definitions, the conversation by role, injected pack context, summaries, and shell output. | Shipped |
16
- | Guarded compaction | `/context compact [instructions]`, `c` on the screen | Compact from the report without interrupting a streaming turn or a running compaction. | Shipped |
17
- | Compact result | `/context compact` result | The before and after token counts are reported, so the effect of the compaction is visible. | Shipped |
18
- | Honest drift | `/context` | The difference between Pi's total and the composition estimate, named instead of hidden by forcing the parts to add up. | Shipped |
19
- | Compaction history | `/context` | How many compactions the branch has, what the newest one cut from and to, and what its summary costs. | Shipped |
20
- | Largest messages | `/context` | The five largest single messages, so a report that is mostly one tool result says so. | Shipped |
21
- | Gauge rendering | the `/context` screen | The window and composition bars show ten or eight cells, colored by role, instead of leaving the reader to infer the shape. | Shipped |
22
- | Pending total | `/context` after a compaction | The report shows a pending total instead of a fabricated estimate while Pi recalculates the window. | Shipped |
23
- | Mode coverage | `/context` | A scrollable screen in the TUI, the same facts as plain text in `rpc`, `json`, and `print`. | Shipped |
10
+ | Capability | How | What you get |
11
+ |---|---|---|
12
+ | Window headline | `/context` | Pi's own estimate: tokens, window, percentage, free space, and the auto-compaction threshold with the headroom left before it. |
13
+ | Composition breakdown | `/context` | Where the window went — system prompt, active tool definitions, the conversation by role, injected pack context, summaries, and shell output. |
14
+ | Guarded compaction | `/context compact [instructions]`, `c` on the screen | Compact from the report without interrupting a streaming turn or a running compaction. |
15
+ | Compact result | `/context compact` result | The before and after token counts are reported, so the effect of the compaction is visible. |
16
+ | Honest drift | `/context` | The difference between Pi's total and the composition estimate, named instead of hidden by forcing the parts to add up. |
17
+ | Compaction history | `/context` | How many compactions the branch has, what the newest one cut from and to, and what its summary costs. |
18
+ | Largest messages | `/context` | The five largest single messages, so a report that is mostly one tool result says so. |
19
+ | Gauge rendering | the `/context` screen | The window and composition bars show ten or eight cells, colored by the row's category — the same hue in the composition table and in the largest-message list — instead of leaving the reader to infer the shape. |
20
+ | Pending total | `/context` after a compaction | The report shows a pending total instead of a fabricated estimate while Pi recalculates the window. |
21
+ | Mode coverage | `/context` | A scrollable screen in the TUI, the same facts as plain text in `rpc`, `json`, and `print`. |
24
22
 
25
23
  ## Quickstart
26
24
 
@@ -83,6 +81,28 @@ first reply, when Pi's fallback leaves the prompt and the tools out. Each bar
83
81
  rounds to the nearest cell, so a bar sits within half a cell of the percentage
84
82
  printed beside it; the percentage itself is exact.
85
83
 
84
+ ## The table is a chart
85
+
86
+ A row's bar and its percentage wear the hue of its category, and the
87
+ largest-message list uses the same table, so a tool result is one colour wherever
88
+ it appears. A hue identifies; it never judges — the gauge is the only verdict on
89
+ the screen, and the footer's feedback line is the transient one. Labels, token
90
+ counts, and notes stay in the body, secondary, and faint roles, so the text still
91
+ reads on its own and the colour repeats an order the row already has.
92
+
93
+ | Category | Hue | Bucket ids |
94
+ |---|---|---|
95
+ | System prompt | blue (`hue1`) | `system` |
96
+ | Tool definitions | purple (`hue2`) | `tools` |
97
+ | User messages | pink (`hue3`) | `user` |
98
+ | Assistant | green (`hue4`) | `assistant` |
99
+ | Tool results | amber (`hue5`) | `toolResults`, the `tool result` rows |
100
+ | Everything else | neutral (`meta`, children `faint`) | injected context and its children, summaries, shell output |
101
+
102
+ A category with no entry — an injected type, a role a future Pi adds — reads
103
+ neutral rather than borrowing a hue, so the coloured rows always mean the five
104
+ categories above.
105
+
86
106
  | Row | Source |
87
107
  |---|---|
88
108
  | Headline (`tokens`, `percent`) | `ctx.getContextUsage()`: the last valid provider usage plus Pi's estimate of the messages after it. `tokens` is `null` between a compaction and the next successful reply, because the last usage describes the pre-compaction context. |
@@ -175,7 +195,7 @@ printed beside it; the percentage itself is exact.
175
195
  | `collect.ts` | The host boundary: one read of usage, prompt, tools, settings, projection, and branch. |
176
196
  | `report.ts` | The pure builder: composition, reserve resolution, compaction history, largest messages. |
177
197
  | `format.ts` | The plain-text report for non-TUI modes. |
178
- | `tui.ts` | `ContextComponent`: gauge, rows, scroll, confirmation, feedback. |
198
+ | `view/context-report.ts` | `ContextComponent`: gauge, rows, scroll, confirmation, feedback, loaded on first use. |
179
199
  | `types.ts` | `ContextInputs`, `ContextReport`, buckets, and the host types named through `ReturnType<…>`. |
180
200
 
181
201
  ## Testing
@@ -12,30 +12,28 @@ the shared loopback layer plus one small vanilla script.
12
12
 
13
13
  ## Capabilities
14
14
 
15
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
16
-
17
- | Capability | How | What you get | Status |
18
- |---|---|---|---|
19
- | One-command browsing | `/browse` | The server starts at the effective working directory, prints its URL, and opens the browser. | Shipped |
20
- | Read-only serving | `/browse` | Nothing is edited or written, and the server binds `127.0.0.1` only. | Shipped |
21
- | Two-pane page | `/files/`, `/files/browse[/<rel>]` | A collapsible tree beside the current folder's listing, with the tree, filter, and quick-open trigger pinned in their own pane. | Shipped |
22
- | File previews | `/view/<rel>` | Text, rendered Markdown, image thumbnails, and download cards for binary or over-size files, each with a per-language icon. | Shipped |
23
- | Quick open | `/files/`, `Ctrl/Cmd+K`, `/files/api/files` | A fuzzy path finder over the tree opens a file without walking the tree. | Shipped |
24
- | Git diff view | `/diff`, `/diff/<rel>` | A change overview and one file's unified diff, scoped to `head`, `staged`, or `worktree`. | Shipped |
25
- | Live status | `/events`, the `◉ live` chip | An open page keeps its branch, change markers, and footer up to date without a reload. | Shipped |
26
- | Reload hint | `/api/dir-rev`, `⟳ reload` | A page whose folder gained or lost a file offers a reload control instead of changing its rows. | Shipped |
27
- | The session's page port | `serve`'s `◉ <port>` chip | The footer names the one port every page of the session answers on, this one included. | Shipped |
28
- | Listing controls | the `Name`, `Size`, and `Modified` headers | The current folder sorts by name, size, or modified time, directories first, and the choice is remembered per browser. | Shipped |
29
- | Keyboard navigation | the tree's keymap, `?` | The tree is one tab stop with arrow, fold, and open keys; a shortcut sheet lists the page's own keys. | Shipped |
30
- | Diff hunk navigation | `n`/`p` in `/diff` | Jump between changed hunks without scrolling the whole file. | Shipped |
31
- | Fold and expand all | the `fold all` control | Collapse or expand the whole tree in one click. | Shipped |
32
- | Reading progress | `browse-progress` hairline | A long directory or diff read shows how much has loaded, and printing hides the indicator. | Shipped |
33
- | Printing | `@media print` styles | The page prints without the toolbar, progress hairline, or other screen-only chrome. | Shipped |
34
- | Syntax highlighting | `/view/<rel>`, `/view/<rel>?raw=1` | Supported code files show keywords, strings, numbers, and comments in colour in both themes; other text stays plain. | Shipped |
35
- | Markdown preview | `/view/<rel>`, `/view/<rel>?raw=1` | A README renders as headings, lists, tables, code, and links, with a one-click raw view. | Shipped |
36
- | Copy and wrap | the page toolbar, `y`, `u` | Copy a file's path or contents or a `path:12-30` line reference, and toggle line wrapping for text and raw views. | Shipped |
37
- | Theme toggle | the header button, `/theme.js` | Dark and light palettes, following the system until an explicit choice is remembered per browser. | Shipped |
38
- | Idle stop and prefix reuse | `/browse stop`, the idle grace | The page gives its prefix back when nobody is reading it, so a closed tab never holds the session's server. | Shipped |
15
+ | Capability | How | What you get |
16
+ |---|---|---|
17
+ | One-command browsing | `/browse` | The server starts at the effective working directory, prints its URL, and opens the browser; every later `/browse` opens the page it already serves. |
18
+ | Read-only serving | `/browse` | Nothing is edited or written, and the server binds `127.0.0.1` only. |
19
+ | Two-pane page | `/files/`, `/files/browse[/<rel>]` | A collapsible tree beside the current folder's listing, with the tree, filter, and quick-open trigger pinned in their own pane. |
20
+ | File previews | `/view/<rel>` | Text, rendered Markdown, image thumbnails, and download cards for binary or over-size files, each with a per-language icon. |
21
+ | Quick open | `/files/`, `Ctrl/Cmd+K`, `/files/api/files` | A fuzzy path finder over the tree opens a file without walking the tree. |
22
+ | Git diff view | `/diff`, `/diff/<rel>` | A change overview and one file's unified diff, scoped to `head`, `staged`, or `worktree`. |
23
+ | Live status | `/events`, the `◉ live` chip | An open page keeps its branch, change markers, and footer up to date without a reload. |
24
+ | Reload hint | `/api/dir-rev`, `⟳ reload` | A page whose folder gained or lost a file offers a reload control instead of changing its rows. |
25
+ | The session's page port | `serve`'s `◉ <port>` chip | The footer names the one port every page of the session answers on, this one included. |
26
+ | Listing controls | the `Name`, `Size`, and `Modified` headers | The current folder sorts by name, size, or modified time, directories first, and the choice is remembered per browser. |
27
+ | Keyboard navigation | the tree's keymap, `?` | The tree is one tab stop with arrow, fold, and open keys; a shortcut sheet lists the page's own keys. |
28
+ | Diff hunk navigation | `n`/`p` in `/diff` | Jump between changed hunks without scrolling the whole file. |
29
+ | Fold and expand all | the `fold all` control | Collapse or expand the whole tree in one click. |
30
+ | Reading progress | `browse-progress` hairline | A long directory or diff read shows how much has loaded, and printing hides the indicator. |
31
+ | Printing | `@media print` styles | The page prints without the toolbar, progress hairline, or other screen-only chrome. |
32
+ | Syntax highlighting | `/view/<rel>`, `/view/<rel>?raw=1` | Supported code files show keywords, strings, numbers, and comments in colour in both themes; other text stays plain. |
33
+ | Markdown preview | `/view/<rel>`, `/view/<rel>?raw=1` | A README renders as headings, lists, tables, code, and links, with a one-click raw view. |
34
+ | Copy and wrap | the page toolbar, `y`, `u` | Copy a file's path or contents or a `path:12-30` line reference, and toggle line wrapping for text and raw views. |
35
+ | Theme toggle | the header button, `/theme.js` | Dark and light palettes, following the system until an explicit choice is remembered per browser. |
36
+ | Idle stop and prefix reuse | `/browse stop`, the idle grace | The page gives its prefix back when nobody is reading it, so a closed tab never holds the session's server. |
39
37
 
40
38
  ## Quickstart
41
39
 
@@ -66,11 +64,12 @@ selects the root.
66
64
 
67
65
  - The root is the effective cwd, so an active `worktree` session serves the
68
66
  worktree. `<path>` must resolve inside it.
69
- - The port is the session's: `serve` picks one in `4780`–`5779` (and `serve.port` pins
70
- it), so the origin stays stable across roots and restarts. A busy pinned port is
71
- reported, not silently changed.
72
- - Starting while already running with the same root reprints the URL without
73
- restarting; a different root restarts the page.
67
+ - The port is the project's: `serve` hashes the repository key into `4780`–`5779`
68
+ (and `serve.port` pins it), so the origin stays stable across roots and restarts. A
69
+ busy pinned port is reported, not silently changed.
70
+ - Starting while already running with the same root opens that page again and
71
+ reprints its URL, without restarting the server; a different root restarts the page.
72
+ With `autoOpen` off, the second `/browse` only reprints the URL.
74
73
  - The server is closed when its last page has been gone for ten seconds, so
75
74
  closing the browser window ends the session's browse server and `/browse`
76
75
  starts it again on the session's port. A reload or a new tab inside that grace keeps
@@ -101,7 +100,7 @@ global document then project document, project wins — are in
101
100
 
102
101
  | Key | Default | Meaning |
103
102
  |---|---|---|
104
- | `autoOpen` | `true` | Open the browser on start; `false` for headless. |
103
+ | `autoOpen` | `true` | Open the browser on start and on every later `/browse`; `false` for headless. |
105
104
  | `maxFileBytes` | `1048576` | Larger files show a download card only. |
106
105
  | `maxThumbBytes` | `5242880` | Larger images get an icon, not a thumbnail. |
107
106
  | `maxTextLines` | `5000` | Rendered lines before truncation. |
@@ -524,7 +523,7 @@ stops at the first difference because the control, not the checker, is the fix.
524
523
  | `view/diff-html.ts` | The unified-diff body: the gutter, the sign, the hunk sections, and per-hunk highlighting |
525
524
  | `transport/router.ts` | Pure request handler: routes, the `/raw` sandbox policy, and the error page |
526
525
  | `transport/server.ts` | This extension's routes over `lib/http`'s loopback server: the request count, the stream cap, and the idle policy |
527
- | [`../../lib/http/index.ts`](../../lib/http/index.ts) | Loopback HTTP layer shared with `plan`: one server entry (`serveHttp`) and the mount contract a page claims a prefix with (`requestMount`), page/script/JSON/event-stream headers, `ServeResponse`, the request-envelope helpers, the event-stream sink and its idle grace |
526
+ | [`../../lib/http/index.ts`](../../lib/http/index.ts) | The served-page kit shared with `plan`: one server entry (`serveHttp`), page/script/JSON/event-stream headers, `ServeResponse`, the request-envelope helpers, the event-stream sink and its idle grace. The mount contract is the leaf [`mount.ts`](../../lib/http/mount.ts), which is the only one a registration graph may reach |
528
527
  | [`../../lib/browser.ts`](../../lib/browser.ts) | Cross-platform browser opener (shared with `plan`) |
529
528
 
530
529
  ## Testing
@@ -7,17 +7,15 @@ effective working directory.
7
7
 
8
8
  ## Capabilities
9
9
 
10
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
11
-
12
- | Capability | How | What you get | Status |
13
- |---|---|---|---|
14
- | Native open | `/open`, `open_path` | The file or directory opens in the application the OS associates with its type. | Shipped |
15
- | Reveal in the file manager | `/open -r`, `open_path` with `reveal: true` | The target is selected in the file manager instead of opened. | Shipped |
16
- | Working-directory resolution | `/open`, `open_path` | A relative path resolves against the effective working directory, so under [`worktree`](./worktree.md) `/open .` opens the isolated worktree. | Shipped |
17
- | Codemode-only exposure | `exposure: "codemode"` | The model cannot call `open_path` directly unless a codemode script asks for it; the table does not promise otherwise. | Shipped |
18
- | Pasted-path cleanup | `/open`, `open_path` | The editor's `@` mention prefix, surrounding quotes, and control characters are stripped before the path is used. | Shipped |
19
- | Failure reporting | `/open`, `open_path` | A missing path, a launcher that cannot start, and a non-zero exit after a successful start on macOS/Linux are reported. | Shipped |
20
- | Session-outliving launch | `/open`, `open_path` | The handler runs detached, so the application outlives the Pi session. | Shipped |
10
+ | Capability | How | What you get |
11
+ |---|---|---|
12
+ | Native open | `/open`, `open_path` | The file or directory opens in the application the OS associates with its type. |
13
+ | Reveal in the file manager | `/open -r`, `open_path` with `reveal: true` | The target is selected in the file manager instead of opened. |
14
+ | Working-directory resolution | `/open`, `open_path` | A relative path resolves against the effective working directory, so under [`worktree`](./worktree.md) `/open .` opens the isolated worktree. |
15
+ | Codemode-only exposure | `exposure: "codemode"` | The model cannot call `open_path` directly unless a codemode script asks for it; the table does not promise otherwise. |
16
+ | Pasted-path cleanup | `/open`, `open_path` | The editor's `@` mention prefix, surrounding quotes, and control characters are stripped before the path is used. |
17
+ | Failure reporting | `/open`, `open_path` | A missing path, a launcher that cannot start, and a non-zero exit after a successful start on macOS/Linux are reported. |
18
+ | Session-outliving launch | `/open`, `open_path` | The handler runs detached, so the application outlives the Pi session. |
21
19
 
22
20
  ## Quickstart
23
21
 
@@ -10,20 +10,18 @@ path tools use.
10
10
 
11
11
  ## Capabilities
12
12
 
13
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
14
-
15
- | Capability | How | What you get | Status |
16
- |---|---|---|---|
17
- | Document extraction | `read_doc` | Plain text from a document or workbook whose bytes the built-in `read` cannot decode. | Shipped |
18
- | Paged reading | `read_doc` (`startIndex`, `maxChars`) | A long file arrives in slices, and a truncated result names the offset to ask for next. | Shipped |
19
- | Workbook text | `read_doc` on `.xlsx` | One `[Sheet]` heading per worksheet followed by tab-separated rows, so the shape of the file survives. | Shipped |
20
- | Confined reads | `read_doc` | A path outside the effective working directory is refused, symlinks resolved, before any parser runs. | Shipped |
21
- | Progress and cancellation | `startToolProgress`, the abort signal | A slow extraction shows `Reading... <elapsed>` and can be cancelled instead of looking dead. | Shipped |
22
- | Bounded extraction | `file-read.maxFileBytes`, `file-read.extractTimeoutMs` | An over-size file or a parser past its deadline fails the read instead of parking the turn. | Shipped |
23
- | Per-format switches | `file-read.formats` | Any of the six formats can be turned off, and a disabled read names the key that did it. | Shipped |
24
- | Unsupported-format hint | `read_doc` on another extension | The refusal names the supported formats and the legacy `.xls` conversion hint instead of a generic read error. | Shipped |
25
- | Lazy parsers | `read_doc` | Only the format you read loads a library, so registration costs nothing at startup. | Shipped |
26
- | Code-point slicing | `read_doc` (`startIndex`, `maxChars`) | CJK and emoji stay well-formed across a page boundary. | Shipped |
13
+ | Capability | How | What you get |
14
+ |---|---|---|
15
+ | Document extraction | `read_doc` | Plain text from a document or workbook whose bytes the built-in `read` cannot decode. |
16
+ | Paged reading | `read_doc` (`startIndex`, `maxChars`) | A long file arrives in slices, and a truncated result names the offset to ask for next. |
17
+ | Workbook text | `read_doc` on `.xlsx` | One `[Sheet]` heading per worksheet followed by tab-separated rows, so the shape of the file survives. |
18
+ | Confined reads | `read_doc` | A path outside the effective working directory is refused, symlinks resolved, before any parser runs. |
19
+ | Progress and cancellation | `startToolProgress`, the abort signal | A slow extraction shows `Reading... <elapsed>` and can be cancelled instead of looking dead. |
20
+ | Bounded extraction | `file-read.maxFileBytes`, `file-read.extractTimeoutMs` | An over-size file or a parser past its deadline fails the read instead of parking the turn. |
21
+ | Per-format switches | `file-read.formats` | Any of the six formats can be turned off, and a disabled read names the key that did it. |
22
+ | Unsupported-format hint | `read_doc` on another extension | The refusal names the supported formats and the legacy `.xls` conversion hint instead of a generic read error. |
23
+ | Lazy parsers | `read_doc` | Only the format you read loads a library, so registration costs nothing at startup. |
24
+ | Code-point slicing | `read_doc` (`startIndex`, `maxChars`) | CJK and emoji stay well-formed across a page boundary. |
27
25
 
28
26
  ## Quickstart
29
27
 
@@ -5,21 +5,19 @@ every turn. The goal is the *what*; the [`todo`](./todo.md) list is the *how*.
5
5
 
6
6
  ## Capabilities
7
7
 
8
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
9
-
10
- | Capability | How | What you get | Status |
11
- |---|---|---|---|
12
- | Goal recording | `goal`, `/goal set`, `/goal raw`, `/goal clear` | The objective is replaced whole, cleared by an empty value, and recorded verbatim when you ask for it. | Shipped |
13
- | Phase tracking | `goal`, `/goal done` | The goal is `planning`, `active`, or `achieved`, and only the workflow can open a draft. | Shipped |
14
- | Plan-first question | `goal`, `/goal <prompt>`, `/goal raw` | One dialog decides whether a new goal enters plan mode before it is pursued. | Shipped |
15
- | Plan-mode allowlist | `goal` in plan mode | The model can record or update the objective while plan mode keeps the rest of the session read-only. | Shipped |
16
- | Plan-phase settlement | `planning` goal, `exit_plan_mode` | Leaving plan mode without approval makes the draft `active`; approving the plan writes its `## Goal` into it. | Shipped |
17
- | Understanding loop | `/goal <prompt>`, `/goal set`, `/goal edit` | A typed goal is restated, questioned when it is unclear, and confirmed in the editor before it is recorded. | Shipped |
18
- | Goal rail | the `Goal · active · …` widget, the `achieved` key | The objective stays one line above the editor while it is pursued. | Shipped |
19
- | Per-turn restatement | the `[SESSION GOAL]` reminder | The model reads the pursued objective before each turn, without it entering the transcript. | Shipped |
20
- | Open-list check | `goal`, `/goal done` | Completing the goal names the todo items the list still has open. | Shipped |
21
- | Branch-following state | tool-result `details`, the `goal` session entry | The goal survives `/resume` and `/tree`, and abandoned branches never leak in. | Shipped |
22
- | Command help | `/goal help`, `/goal -h`, `/goal --help` | The verb list and the usage of each form, without changing the goal. | Shipped |
8
+ | Capability | How | What you get |
9
+ |---|---|---|
10
+ | Goal recording | `goal`, `/goal set`, `/goal raw`, `/goal clear` | The objective is replaced whole, cleared by an empty value, and recorded verbatim when you ask for it. |
11
+ | Phase tracking | `goal`, `/goal done` | The goal is `planning`, `active`, or `achieved`, and only the workflow can open a draft. |
12
+ | Plan-first question | `goal`, `/goal <prompt>`, `/goal raw` | One dialog decides whether a new goal enters plan mode before it is pursued. |
13
+ | Plan-mode allowlist | `goal` in plan mode | The model can record or update the objective while plan mode keeps the rest of the session read-only. |
14
+ | Plan-phase settlement | `planning` goal, `plan` action `exit` | Leaving plan mode without approval makes the draft `active`; approving the plan writes its `## Goal` into it. |
15
+ | Understanding loop | `/goal <prompt>`, `/goal set`, `/goal edit` | A typed goal is restated, questioned when it is unclear, and confirmed in the editor before it is recorded. |
16
+ | Goal rail | the `Goal · active · …` widget, the `achieved` key | The objective stays one line above the editor while it is pursued. |
17
+ | Per-turn restatement | the `[SESSION GOAL]` reminder | The model reads the pursued objective before each turn, without it entering the transcript. |
18
+ | Open-list check | `goal`, `/goal done` | Completing the goal names the todo items the list still has open. |
19
+ | Branch-following state | tool-result `details`, the `goal` session entry | The goal survives `/resume` and `/tree`, and abandoned branches never leak in. |
20
+ | Command help | `/goal help`, `/goal -h`, `/goal --help` | The verb list and the usage of each form, without changing the goal. |
23
21
 
24
22
  ## Quickstart
25
23
 
@@ -137,7 +135,7 @@ and stores the objective as `planning`, so a plan can be designed against it;
137
135
  declining stores it `active`, the final objective. The question is skipped for
138
136
  an update to a goal that is already pursued, without a dialog UI, and when
139
137
  `plan` is not loaded. The question and its consent sentence come from
140
- `lib/plan-entry.ts`, the same ones `enter_plan_mode` shows, so the user answers
138
+ `lib/plan-entry.ts`, the same ones the `enter` action shows, so the user answers
141
139
  once.
142
140
 
143
141
  A draft whose plan never arrived is settled rather than stranded. If plan mode is
@@ -215,7 +213,7 @@ that is what it is. The `goal` tool stays the silent setter.
215
213
  the extension that asks also has to act on the answer — which a command context
216
214
  cannot do, since `ExtensionCommandContext` has no `executeTool`. So the consent
217
215
  sentence and the request channel live in `lib/plan-entry.ts`: `goal` asks, and
218
- `plan` enables silently over `pi.events`. `enter_plan_mode` keeps its own
216
+ `plan` enables silently over `pi.events`. The `enter` action keeps its own
219
217
  confirm for the model-initiated path, using the same sentence, so the user is
220
218
  never asked twice and the two texts cannot drift.
221
219
  - **The draft is settled, not stranded.** A `planning` goal is normalised by the
@@ -7,25 +7,23 @@ for it, or kill it.
7
7
 
8
8
  ## Capabilities
9
9
 
10
- Status records what a reader can rely on: **Shipped** is in a tagged release, **Unreleased** is complete in the current tree but not yet tagged, and **Partial** has one released part and one unreleased part. Rows are ordered by user value, highest first.
11
-
12
- | Capability | How | What you get | Status |
13
- |---|---|---|---|
14
- | Background execution | `job` (`start`) | A long build, test suite, server, or watcher keeps running while the turn moves on. | Shipped |
15
- | Job listing | `job` (`list`), `/jobs` | This session's jobs with status and elapsed time, and a live peer session's tagged `peer`. | Shipped |
16
- | Polling and waiting | `job` (`status`, `logs`, `wait`) | One call returns a job's status, a bounded output tail, or blocks until it finishes. | Shipped |
17
- | Stopping jobs | `job` (`kill` with `signal`) | A running job receives `SIGTERM`, `SIGKILL`, or `SIGINT`, and a finished one can be cleared. | Shipped |
18
- | Selective clear | `job` (`clear` with `id`, `all`) | Clear one finished record by id, or remove running jobs with `all` after a confirmation in the screen. | Shipped |
19
- | Start deadline | `timeoutMs` on `start` | A job is killed after the requested wall-clock limit instead of running until the session ends. | Shipped |
20
- | Kill escalation | `killGraceMs` | A kill sends `SIGTERM` first, then `SIGKILL` after the grace period, on a user kill and on shutdown. | Shipped |
21
- | Stdin driving | `job` (`send` with `input`, `newline`, `eof`) | A line or a bare keystroke reaches a running job started with `stdin: true`, and `eof` closes its input. | Shipped |
22
- | Rotating logs | `job` (`logs`), `job.maxLogBytes` | stdout and stderr stream to an append-only log that rotates at 8 MiB, so a chatty job cannot fill the disk. | Shipped |
23
- | Status chips | `job.showStatus` | `▸ N` running and `✗ N` unreported-failure counts in the footer. | Shipped |
24
- | Completion reporting | `job` (`wake`), `job.wakeOnFinish` | A finished job is reported at the next turn, or triggers one as soon as the agent is idle. | Shipped |
25
- | Job screen | `/jobs` | Select a job, open its log, kill it, or clear finished ones, with a confirmation on the destructive verbs. | Shipped |
26
- | Detached lifetime | `job` (`start`, `detached`) | A POSIX job outlives the session and is reattached next time; Windows refuses the detach instead of faking one. | Shipped |
27
- | Finished-job pruning | `maxJobs` | The registry drops the oldest finished records once the configured count is exceeded. | Shipped |
28
- | Structured result | tool-result `details` | Every call returns a `JobDetails` record of the job and the action's outcome. | Shipped |
10
+ | Capability | How | What you get |
11
+ |---|---|---|
12
+ | Background execution | `job` (`start`) | A long build, test suite, server, or watcher keeps running while the turn moves on. |
13
+ | Job listing | `job` (`list`), `/jobs` | This session's jobs with status and elapsed time, and a live peer session's tagged `peer`. |
14
+ | Polling and waiting | `job` (`status`, `logs`, `wait`) | One call returns a job's status, a bounded output tail, or blocks until it finishes. |
15
+ | Stopping jobs | `job` (`kill` with `signal`) | A running job receives `SIGTERM`, `SIGKILL`, or `SIGINT`, and a finished one can be cleared. |
16
+ | Selective clear | `job` (`clear` with `id`, `all`) | Clear one finished record by id, or remove running jobs with `all` after a confirmation in the screen. |
17
+ | Start deadline | `timeoutMs` on `start` | A job is killed after the requested wall-clock limit instead of running until the session ends. |
18
+ | Kill escalation | `killGraceMs` | A kill sends `SIGTERM` first, then `SIGKILL` after the grace period, on a user kill and on shutdown. |
19
+ | Stdin driving | `job` (`send` with `input`, `newline`, `eof`) | A line or a bare keystroke reaches a running job started with `stdin: true`, and `eof` closes its input. |
20
+ | Rotating logs | `job` (`logs`), `job.maxLogBytes` | stdout and stderr stream to an append-only log that rotates at 8 MiB, so a chatty job cannot fill the disk. |
21
+ | Status chips | `job.showStatus` | `▸ N` running and `✗ N` unreported-failure counts in the footer. |
22
+ | Completion reporting | `job` (`wake`), `job.wakeOnFinish` | A finished job is reported at the next turn, or triggers one as soon as the agent is idle. |
23
+ | Job screen | `/jobs` | Select a job, open its log, kill it, or clear finished ones, with a confirmation on the destructive verbs. |
24
+ | Detached lifetime | `job` (`start`, `detached`) | A POSIX job outlives the session and is reattached next time; Windows refuses the detach instead of faking one. |
25
+ | Finished-job pruning | `maxJobs` | The registry drops the oldest finished records once the configured count is exceeded. |
26
+ | Structured result | tool-result `details` | Every call returns a `JobDetails` record of the job and the action's outcome. |
29
27
 
30
28
  ## Quickstart
31
29
 
@@ -210,7 +208,7 @@ are in
210
208
  | `maxLogBytes` | `8388608` | Bytes a log segment may reach before it rotates to `<id>.log.1`; `0` keeps logs unbounded. |
211
209
  | `killGraceMs` | `5000` | Grace before SIGTERM escalates to SIGKILL. |
212
210
  | `repaintMs` | `1000` | Status-chip refresh interval while jobs run. |
213
- | `sessionTtlMs` | `60000` | How long a session heartbeat is trusted before its jobs may be reaped. |
211
+ | `sessionTtlMs` | `60000` | How old a session heartbeat may be before its pid is re-checked for reuse. |
214
212
  | `registryDir` | — | Override the registry/log directory. |
215
213
 
216
214
  ## Security
@@ -236,7 +234,9 @@ rewritten.
236
234
  kill or clear it, and the tool's `clear` refuses that record too; the tool can
237
235
  still take one over by explicit id (`status`/`logs`/`kill`, where `kill`
238
236
  adopts it). Chips, completion notices, and pruning stay this session's own, so
239
- a peer's finished job waits for that session to clear it.
237
+ a peer's finished job waits for that session to clear it — including when that
238
+ session has been idle long enough for its heartbeat to age, because the
239
+ heartbeat only ticks while a job is running.
240
240
  - **A carriage return is not a line break.** Output is split on `\n` only; a
241
241
  progress rewrite (`10%\r50%\r100%`) is one line whose sanitized form keeps the
242
242
  text after the last `\r`. A program that only ever emits `\r` therefore
@@ -279,7 +279,7 @@ rewritten.
279
279
  | `outputSchema` / `structuredContent` | None. Results return `JobDetails` in tool-result `details` only. |
280
280
  | State storage | One durable registry file per session, `~/.pi/agent/jobs/<projectKey>/registry-<sessionHash>.json` (keyed by the session cwd, so entering a worktree does not move it), merged from every session file on load; a dead session's records are adopted and a legacy shared `registry.json` is migrated once. Ids are reserved with an atomic `O_EXCL` `<id>.lock` before `start`, and a POSIX job's exit code is written to a per-job `.status` file. Tool results carry `JobDetails`; unreported completions arrive as a shared transcript notice (`my-pi-agent/notice`) at `before_agent_start`. |
281
281
  | Lifecycle | `session_start` loads and reconciles the registry and arms `onFinish` and `onComplete`; `session_shutdown` kills session-owned jobs and clears both status chips. `session_tree` repaints; `agent_start`/`agent_settled` track busy; `context` prunes stale notices of its own source. |
282
- | Event bus | Each job that reaches a terminal state is published on `my-pi-agent/job-finished` (`lib/events.ts`) with its id, label, status, exit code, and signal, from the one `settle` path every transition goes through. bytefly's notify capability subscribes there instead of importing this extension. |
282
+ | Event bus | Each job that reaches a terminal state is published on `my-pi-agent/job-finished` (`lib/events.ts`) with its id, label, status, exit code, and signal, from the one path every transition goes through — a close event, a pid observed gone on the clock, a gone peer's leftover reaped, and an orphan killed while the registry loads — which announces the completion and fires the one wake turn together. A peer's record settled here is adopted, so its completion is this session's to report. bytefly's notify capability subscribes there instead of importing this extension. |
283
283
 
284
284
  ## Design notes
285
285
 
@@ -322,10 +322,13 @@ rewritten.
322
322
  per session, `start` claims the next `j<n>` with an `O_EXCL` `<id>.lock`
323
323
  before spawning, so two sessions cannot pick the same id from a stale read;
324
324
  the reservation is pruned once the id is committed to a registry file.
325
- - **Sessions heartbeat; reconciliation is owner-aware.** Each session writes a
326
- liveness marker, so a peer's live non-detached job is not reaped until its
327
- owner's marker expires. `persist` merges onto a fresh read and drops ids this
328
- session deleted.
325
+ - **Sessions heartbeat; ownership is the process.** Each session writes a liveness
326
+ marker (its pid, that process's start time, and its last beat), and the beat only
327
+ ticks while a job runs — so a session that has finished its work goes quiet rather
328
+ than dying. Only a session that is *gone* — its pid is dead, or a reused one —
329
+ gives up its records: a quiet peer keeps its file, its marker, and its jobs, and a
330
+ peer's live non-detached job is never reaped. `persist` merges onto a fresh read and
331
+ drops ids this session deleted.
329
332
  - **Exit codes survive a session boundary.** A POSIX job is spawned behind an
330
333
  `EXIT` trap that writes `$?` to a per-job `.status` file (path passed in the
331
334
  environment); a later session reads it when it finds a dead pid and reports
@@ -336,14 +339,17 @@ rewritten.
336
339
  `detached` dev server survives.
337
340
  - **Pid reuse is guarded by a start-time token.** Before signalling an unowned
338
341
  pid, its best-effort start token (`ps -o lstart=`) is re-checked; a mismatch
339
- is treated as gone instead of as a signal. Where no token is available the
340
- check degrades to liveness.
342
+ is treated as gone instead of as a signal. The same token is written into a
343
+ session's marker, so a pid that has been reused is a gone session rather than a
344
+ quiet one. Where no token is available the check degrades to liveness.
341
345
  - **Reattached jobs are polled.** A reattached detached job has no child
342
346
  handle, so its `close` event never fires; the repaint clock polls it and
343
347
  settles it (recovering an exit code from the status file, else `unknown`)
344
348
  when the pid disappears.
345
349
  - **Shared seams, job policy.** The spawn/tree-kill/liveness seam
346
- (`lib/spawn.ts`), the byte-safe line splitter (`lib/lines.ts`), the
350
+ (`lib/spawn.ts`), the command supervisor (`lib/child.ts`, which `watch` drives
351
+ too: one SIGTERM → SIGKILL body, each extension's own grace), the byte-safe
352
+ line splitter (`lib/lines.ts`), the
347
353
  untrusted-line boundary (`lib/format.ts`), the pending-report coordinator
348
354
  (`lib/report.ts`), the status chips (`lib/tui/status-controller.ts`), and the
349
355
  `/jobs` screen frame (`lib/tui/dock-screen.ts`) are shared with `watch`; this
@@ -387,19 +393,22 @@ rewritten.
387
393
  | `index.ts` | Factory: registers the tool/command and wires events, including the shared `lib/report.ts` completion reporter. |
388
394
  | `schema.ts` | Parameter schema and pure validation (a `JobCall` union). |
389
395
  | `config.ts` | The `job` section of `bytefly.json`: loading and clamping. |
390
- | `format.ts` | Pure formatting, duration, and transcript outcome-line helpers; sanitization is `lib/format.ts`'s `sanitizeUntrustedLine`. |
396
+ | `format.ts` | Pure formatting, duration, and transcript outcome-line helpers, plus the job row both surfaces draw; sanitization is `lib/format.ts`'s `sanitizeUntrustedLine`. |
391
397
  | `paths.ts` | Session/marker/registry/status file-name helpers. |
392
- | `registry.ts` | Per-session registry load/merge, legacy migration, and pure reconciliation. |
398
+ | `registry.ts` | Per-session registry load/merge under `<agent-dir>/jobs/<project>/`, legacy migration, and the pure reconciliation a load runs — `loadRecords` merges every file, recovers dead pids, and classifies the survivors and orphans. |
393
399
  | `reservations.ts` | Atomic `O_EXCL` job-id reservation and release. |
394
400
  | `status.ts` | `EXIT`-trap exit-status file (write path via env, read on reattach). |
395
- | `session.ts` | Per-session heartbeat markers and owner-liveness rules. |
396
- | `store.ts` | Durable store: registry dir, this session's atomic merge-write, deletions. |
401
+ | `session.ts` | Per-session heartbeat markers and the ownership rule: `live`, `quiet`, or `gone`. |
402
+ | `store.ts` | Durable store: the registry directory (`<agent-dir>/jobs/<project>/`), this session's atomic merge-write, deletions. |
397
403
  | `logs.ts` | Bounded, sanitized log-tail reading. |
398
404
  | `ui.ts` | Footer status chips and the failure alert, over the shared `lib/tui/status-controller.ts` (chips, attached context, `notify`). |
399
405
  | `waiters.ts` | `wait` resolver bookkeeping. |
400
406
  | `log-writer.ts` | Per-job log sink: write stream, line split, rotation queue, and the output-driven repaint window. |
401
- | `runtime.ts` | Composition: job table, child handles, process events, repaint clock. |
402
- | `tui.ts` | The `/jobs` screen (a `DockListScreen` subclass: job rows, focus block, counts, verbs) and the `JobResult` transcript block over the shared `TailResult`. |
407
+ | `runtime.ts` | The job table and the durable record: load and reconcile, the one settle path that announces a completion and its wake turn (holding either until the session arms its listener), waiters, clear, shutdown. |
408
+ | `child.ts` | A job's process and its output: the spawn policy, the handle, the log stream and stdin, close/error settle, the signal and its SIGKILL grace, and the files a job leaves, over the shared `lib/child.ts` supervisor. |
409
+ | `clock.ts` | The periodic work: the repaint clock that re-asserts the chip, and the sweep that polls the jobs this session reattached. |
410
+ | `render.ts` | The `JobResult` transcript block over the shared `TailResult`. |
411
+ | `view/jobs-screen.ts` | The `/jobs` screen (a `DockListScreen` subclass: job rows, focus block, counts, verbs), loaded on first use. |
403
412
  | `tools.ts` | The `job` tool and its transcript rendering. |
404
413
  | `commands.ts` | The `/jobs` command. |
405
414
  | `types.ts` | Shared types. |
@@ -409,10 +418,13 @@ rewritten.
409
418
  `extensions/job/` covers schema validation (`schema`), pure formatting and
410
419
  sanitization (`format`), the durable store (`store`), per-session reconciliation
411
420
  (`registry`), id reservation (`reservations`), exit-status recovery (`status`),
412
- session markers (`session`), bounded log reads and tail flags (`logs`), wait
413
- bookkeeping (`waiters`), the `job` tool (`tools`), the `/jobs` screen (`tui`),
414
- the runtime's session-scoped list and failure notification (`runtime`), `send`
415
- to a job's stdin and the pipe's lifecycle (`runtime`), log rotation, its two
416
- segments, and the cross-segment read (`runtime`), and the
417
- install/resume/shutdown lifecycle (`extension`). Tests drive a scripted
418
- `FakeChild` and a temp registry, so the suite runs without launching a process.
421
+ session markers and the ownership rule (`session`), bounded log reads and tail
422
+ flags (`logs`), log rotation and its two segments (`log-writer`), wait
423
+ bookkeeping and the wait promise (`waiters`), the `job` tool (`tools`), the
424
+ `/jobs` screen (`view/jobs-screen`), the table's session-scoped list,
425
+ reattachment, clear and failure notification (`runtime`), a job's spawn, finish,
426
+ kill, Windows policy, detached output, bounded tail and pid questions (`child`),
427
+ `send` to a job's stdin and the pipe's lifecycle (`stdin`), the repaint clock and
428
+ the external sweep (`clock`), and the install/resume/shutdown lifecycle
429
+ (`extension`). Tests drive a scripted `FakeChild` and a temp registry, so the
430
+ suite runs without launching a process.