@astralyn/pi 0.84.14 → 0.84.15

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 (178) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/core/agent-session.d.ts.map +1 -1
  3. package/dist/core/agent-session.js +12 -6
  4. package/dist/core/agent-session.js.map +1 -1
  5. package/dist/core/extensions/types.d.ts +4 -1
  6. package/dist/core/extensions/types.d.ts.map +1 -1
  7. package/dist/core/extensions/types.js.map +1 -1
  8. package/dist/core/tools/bash.d.ts +1 -0
  9. package/dist/core/tools/bash.d.ts.map +1 -1
  10. package/dist/core/tools/bash.js +4 -1
  11. package/dist/core/tools/bash.js.map +1 -1
  12. package/dist/core/tools/find.d.ts +2 -0
  13. package/dist/core/tools/find.d.ts.map +1 -1
  14. package/dist/core/tools/find.js +18 -15
  15. package/dist/core/tools/find.js.map +1 -1
  16. package/dist/extensions/background/actions.d.ts.map +1 -1
  17. package/dist/extensions/background/actions.js +3 -2
  18. package/dist/extensions/background/actions.js.map +1 -1
  19. package/dist/extensions/background/manager.d.ts.map +1 -1
  20. package/dist/extensions/background/manager.js +8 -9
  21. package/dist/extensions/background/manager.js.map +1 -1
  22. package/dist/extensions/background/registry.d.ts +4 -1
  23. package/dist/extensions/background/registry.d.ts.map +1 -1
  24. package/dist/extensions/background/registry.js +30 -17
  25. package/dist/extensions/background/registry.js.map +1 -1
  26. package/dist/extensions/background/task-view.d.ts +6 -0
  27. package/dist/extensions/background/task-view.d.ts.map +1 -1
  28. package/dist/extensions/background/task-view.js +11 -6
  29. package/dist/extensions/background/task-view.js.map +1 -1
  30. package/dist/extensions/deepwiki/client.d.ts.map +1 -1
  31. package/dist/extensions/deepwiki/client.js +3 -0
  32. package/dist/extensions/deepwiki/client.js.map +1 -1
  33. package/dist/extensions/deepwiki/execute.d.ts +2 -1
  34. package/dist/extensions/deepwiki/execute.d.ts.map +1 -1
  35. package/dist/extensions/deepwiki/execute.js +17 -2
  36. package/dist/extensions/deepwiki/execute.js.map +1 -1
  37. package/dist/extensions/deepwiki/http.d.ts +1 -0
  38. package/dist/extensions/deepwiki/http.d.ts.map +1 -1
  39. package/dist/extensions/deepwiki/http.js +16 -2
  40. package/dist/extensions/deepwiki/http.js.map +1 -1
  41. package/dist/extensions/deepwiki/schema.d.ts +1 -1
  42. package/dist/extensions/deepwiki/schema.d.ts.map +1 -1
  43. package/dist/extensions/deepwiki/schema.js +8 -2
  44. package/dist/extensions/deepwiki/schema.js.map +1 -1
  45. package/dist/extensions/question/dialog.d.ts.map +1 -1
  46. package/dist/extensions/question/dialog.js +80 -9
  47. package/dist/extensions/question/dialog.js.map +1 -1
  48. package/dist/extensions/question/index.d.ts.map +1 -1
  49. package/dist/extensions/question/index.js +8 -0
  50. package/dist/extensions/question/index.js.map +1 -1
  51. package/dist/extensions/question/schema.d.ts +2 -2
  52. package/dist/extensions/question/schema.d.ts.map +1 -1
  53. package/dist/extensions/question/schema.js +41 -11
  54. package/dist/extensions/question/schema.js.map +1 -1
  55. package/dist/extensions/question/types.d.ts +1 -1
  56. package/dist/extensions/question/types.d.ts.map +1 -1
  57. package/dist/extensions/question/types.js.map +1 -1
  58. package/dist/extensions/router/probe.d.ts.map +1 -1
  59. package/dist/extensions/router/probe.js +10 -29
  60. package/dist/extensions/router/probe.js.map +1 -1
  61. package/dist/extensions/router/register.d.ts.map +1 -1
  62. package/dist/extensions/router/register.js +16 -6
  63. package/dist/extensions/router/register.js.map +1 -1
  64. package/dist/extensions/router/store.d.ts.map +1 -1
  65. package/dist/extensions/router/store.js +108 -51
  66. package/dist/extensions/router/store.js.map +1 -1
  67. package/dist/extensions/router/ui.d.ts +6 -0
  68. package/dist/extensions/router/ui.d.ts.map +1 -1
  69. package/dist/extensions/router/ui.js +14 -6
  70. package/dist/extensions/router/ui.js.map +1 -1
  71. package/dist/extensions/statusline/index.d.ts.map +1 -1
  72. package/dist/extensions/statusline/index.js +40 -43
  73. package/dist/extensions/statusline/index.js.map +1 -1
  74. package/dist/extensions/subagent/activity.d.ts +7 -1
  75. package/dist/extensions/subagent/activity.d.ts.map +1 -1
  76. package/dist/extensions/subagent/activity.js +69 -6
  77. package/dist/extensions/subagent/activity.js.map +1 -1
  78. package/dist/extensions/subagent/agents-command.js +1 -1
  79. package/dist/extensions/subagent/agents-command.js.map +1 -1
  80. package/dist/extensions/subagent/agents.d.ts.map +1 -1
  81. package/dist/extensions/subagent/agents.js +0 -3
  82. package/dist/extensions/subagent/agents.js.map +1 -1
  83. package/dist/extensions/subagent/budget.d.ts.map +1 -1
  84. package/dist/extensions/subagent/budget.js +29 -2
  85. package/dist/extensions/subagent/budget.js.map +1 -1
  86. package/dist/extensions/subagent/cancellation.d.ts +4 -4
  87. package/dist/extensions/subagent/cancellation.d.ts.map +1 -1
  88. package/dist/extensions/subagent/cancellation.js +31 -13
  89. package/dist/extensions/subagent/cancellation.js.map +1 -1
  90. package/dist/extensions/subagent/constants.d.ts +1 -0
  91. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  92. package/dist/extensions/subagent/constants.js +1 -0
  93. package/dist/extensions/subagent/constants.js.map +1 -1
  94. package/dist/extensions/subagent/index.d.ts.map +1 -1
  95. package/dist/extensions/subagent/index.js +1 -0
  96. package/dist/extensions/subagent/index.js.map +1 -1
  97. package/dist/extensions/subagent/render.d.ts +8 -1
  98. package/dist/extensions/subagent/render.d.ts.map +1 -1
  99. package/dist/extensions/subagent/render.js +148 -178
  100. package/dist/extensions/subagent/render.js.map +1 -1
  101. package/dist/extensions/subagent/runner.d.ts +1 -0
  102. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  103. package/dist/extensions/subagent/runner.js +53 -44
  104. package/dist/extensions/subagent/runner.js.map +1 -1
  105. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  106. package/dist/extensions/subagent/sdk-runner.js +0 -3
  107. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  108. package/dist/extensions/subagent/settings.d.ts +1 -1
  109. package/dist/extensions/subagent/settings.d.ts.map +1 -1
  110. package/dist/extensions/subagent/settings.js +74 -25
  111. package/dist/extensions/subagent/settings.js.map +1 -1
  112. package/dist/extensions/subagent/state.d.ts +1 -0
  113. package/dist/extensions/subagent/state.d.ts.map +1 -1
  114. package/dist/extensions/subagent/state.js +46 -16
  115. package/dist/extensions/subagent/state.js.map +1 -1
  116. package/dist/extensions/subagent/types.d.ts +0 -7
  117. package/dist/extensions/subagent/types.d.ts.map +1 -1
  118. package/dist/extensions/subagent/types.js.map +1 -1
  119. package/dist/extensions/subagent/ui/agents-dialog.js +1 -1
  120. package/dist/extensions/subagent/ui/agents-dialog.js.map +1 -1
  121. package/dist/extensions/subagent/ui/model-list.d.ts.map +1 -1
  122. package/dist/extensions/subagent/ui/model-list.js +3 -4
  123. package/dist/extensions/subagent/ui/model-list.js.map +1 -1
  124. package/dist/extensions/subagent/ui/model-picker.d.ts.map +1 -1
  125. package/dist/extensions/subagent/ui/model-picker.js +2 -1
  126. package/dist/extensions/subagent/ui/model-picker.js.map +1 -1
  127. package/dist/extensions/web-search/format.d.ts.map +1 -1
  128. package/dist/extensions/web-search/format.js +36 -15
  129. package/dist/extensions/web-search/format.js.map +1 -1
  130. package/dist/extensions/web-search/index.d.ts.map +1 -1
  131. package/dist/extensions/web-search/index.js +11 -8
  132. package/dist/extensions/web-search/index.js.map +1 -1
  133. package/dist/extensions/web-search/providers/deepseek.d.ts.map +1 -1
  134. package/dist/extensions/web-search/providers/deepseek.js +36 -5
  135. package/dist/extensions/web-search/providers/deepseek.js.map +1 -1
  136. package/dist/extensions/web-search/providers/http.d.ts +2 -7
  137. package/dist/extensions/web-search/providers/http.d.ts.map +1 -1
  138. package/dist/extensions/web-search/providers/http.js +12 -57
  139. package/dist/extensions/web-search/providers/http.js.map +1 -1
  140. package/dist/extensions/web-search/providers/minimax.d.ts.map +1 -1
  141. package/dist/extensions/web-search/providers/minimax.js +18 -6
  142. package/dist/extensions/web-search/providers/minimax.js.map +1 -1
  143. package/dist/extensions/web-search/render.d.ts.map +1 -1
  144. package/dist/extensions/web-search/render.js +16 -5
  145. package/dist/extensions/web-search/render.js.map +1 -1
  146. package/dist/extensions/web-search/results.d.ts +10 -3
  147. package/dist/extensions/web-search/results.d.ts.map +1 -1
  148. package/dist/extensions/web-search/results.js +25 -7
  149. package/dist/extensions/web-search/results.js.map +1 -1
  150. package/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  151. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  152. package/dist/modes/interactive/components/tool-execution.js +7 -0
  153. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  154. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/tool-group.js +10 -0
  156. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  157. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  158. package/dist/modes/interactive/interactive-mode.js +3 -40
  159. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  160. package/dist/modes/interactive/theme/theme.d.ts +0 -4
  161. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  162. package/dist/modes/interactive/theme/theme.js +16 -23
  163. package/dist/modes/interactive/theme/theme.js.map +1 -1
  164. package/dist/utils/http-response.d.ts +10 -0
  165. package/dist/utils/http-response.d.ts.map +1 -0
  166. package/dist/utils/http-response.js +68 -0
  167. package/dist/utils/http-response.js.map +1 -0
  168. package/docs/bundled/extensions/background.md +2 -1
  169. package/docs/bundled/extensions/deepwiki.md +7 -5
  170. package/docs/bundled/extensions/question.md +6 -4
  171. package/docs/bundled/extensions/router.md +1 -1
  172. package/docs/bundled/extensions/statusline.md +1 -0
  173. package/docs/bundled/extensions/subagent.md +29 -39
  174. package/docs/bundled/extensions/web-search.md +3 -3
  175. package/docs/development.md +7 -2
  176. package/docs/extensions.md +2 -2
  177. package/npm-shrinkwrap.json +2 -2
  178. package/package.json +1 -1
@@ -91,8 +91,9 @@ Running and finished counts appear in the footer as `bg 2 running · 1 done`; ta
91
91
 
92
92
  - Background tasks inherit the session's `PI_*` environment variables (`PI_SESSION_ID`, `PI_MODEL`, …) just like the built-in bash tool, snapshotted when the task starts.
93
93
  - Tasks run through the session's configured shell (`shellPath`) and honor `shellCommandPrefix`, matching the built-in bash tool. The prefix is applied at execution time only — it never appears in task labels or notifications. Unlike the built-in bash tool, `bg` does not apply an SDK host's `spawnHook` — extensions have no access to it — so a host that rewrites or sandboxes commands through that hook does not cover background tasks.
94
- - Output streams directly to a system-temp file (`pi-bg-<id>.log`), never into the project or into memory. Memory holds only a byte counter.
94
+ - Output streams directly to a system-temp file (`pi-bg-<id>.log`), never into the project or into memory. Memory holds only a byte counter. Task allocation creates the file exclusively and retries a new id on collisions, so a stale log is never overwritten.
95
95
  - Output is capped at 20MB. Hitting the cap kills the task and marks it `failed` rather than silently truncating.
96
+ - The stall watchdog only reports `waiting for input` after it can read a stable prompt-like tail. A temporary tail-read error keeps the task running and eligible for later probes instead of producing a false stall; if the task finishes while its tail remains unreadable, the completion reports that read error.
96
97
  - At most 8 tasks may run concurrently; `create` reports the running tasks when the limit is reached.
97
98
  - Aborting the current turn (Esc) does not kill background tasks — that is what `kill` and `/bg` are for.
98
99
  - Session shutdown, `/reload`, new sessions, and session switches kill all running tasks; those kills are silent (no notification flood). There is no restart reattachment: finished-task records live only for the current session.
@@ -7,9 +7,11 @@ It is intentionally not a general MCP bridge. The extension exposes one dedicate
7
7
  | Action | Behavior |
8
8
  |---|---|
9
9
  | `structure` | List the generated wiki topics for a repository. |
10
- | `contents` | Read the generated wiki — one page via `page` (recommended), or everything when `page` is omitted (truncated past ~120k chars). |
10
+ | `contents` | Read the generated wiki — one page via `page` (recommended), or everything when `page` is omitted. |
11
11
  | `question` | Ask a focused question about a repository. |
12
12
 
13
+ Every action has a hard model-facing limit of 120,000 characters. `contents` prefers page-aware cuts and reports omitted pages; `structure` and `question` use an action-specific truncation notice.
14
+
13
15
  ## Usage
14
16
 
15
17
  ### Parameters
@@ -17,7 +19,7 @@ It is intentionally not a general MCP bridge. The extension exposes one dedicate
17
19
  - `action`: `structure`, `contents`, or `question`
18
20
  - `repoName`: one `owner/repo` string for `structure` and `contents`; for `question`, one repo as a string, or 2–10 repos as an array (comma-separated string also accepted)
19
21
  - `question`: required only for `action: "question"`
20
- - `page`: optional, only for `action: "contents"` — 1-based index or page title from `structure` (plain titles such as `Extension System`, not numbered outline lines like `4.4 …`). Leading outline numbers on titles are stripped when matching. Unknown `page` fails with available titles listed.
22
+ - `page`: optional, only for `action: "contents"` — a positive 1-based integer or page title from `structure` (plain titles such as `Extension System`, not numbered outline lines like `4.4 …`). Zero, negative, fractional, non-finite, and blank values are rejected. Leading outline numbers on titles are stripped when matching. Unknown `page` fails with available titles listed.
21
23
 
22
24
  `repoName` is normalized before validation (`owner/repo`, GitHub/DeepWiki URLs, JSON-array strings for multi-repo mistakes). `pageName`/`pageTitle` are accepted as `page` aliases. If `action` is omitted, defaults to `question` when a question is present, `contents` when `page` is present, else `structure`. Repositories not indexed on DeepWiki return repository-not-found errors — run `structure` first to detect that.
23
25
 
@@ -49,8 +51,8 @@ Avoid DeepWiki when the authoritative source is local or time-sensitive:
49
51
  ## Limits
50
52
 
51
53
  - A repository may not be indexed. DeepWiki can return that as normal text, so the extension treats repository-not-found messages as tool errors.
52
- - `contents` responses are truncated at a ~120k-character budget on `# Page:` boundaries (whole pages kept in order; at least the first page survives, cut mid-page if it alone exceeds the budget). A trailing notice reports shown/total pages, the full length, up to 20 omitted page titles, and points at `page` reads and `action: "question"` for the rest. Details carry `shownPages` / `truncatedChars` when this happens; `outputLength` always reflects the full untruncated response. Single-page reads set `requestedPage` / `pageIndex` instead and share the same budget.
53
- - Network requests time out after 45 seconds and surface as Pi tool errors.
54
+ - All model-facing responses are capped at 120,000 characters. `contents` prefers `# Page:` boundaries (whole pages kept in order; at least the first page survives, cut mid-page if it alone exceeds the budget). Its trailing notice reports shown/total pages, the full length, up to 20 omitted page titles, and points at `page` reads and `action: "question"` for the rest. `structure` and `question` append a focused-request truncation notice. Details carry `shownPages` / `truncatedChars` when applicable; `outputLength` always reflects the full cached response. Single-page reads set `requestedPage` / `pageIndex` and share the same hard budget.
55
+ - Each transport response is streamed with an 8 MiB byte limit before JSON/SSE parsing; oversized, failed, aborted, and timed-out responses never enter the cache. Network attempts time out after 45 seconds and surface as Pi tool errors.
54
56
  - Use local Pi tools (`read`, `grep`, `find`, `ls`) for workspace state. DeepWiki answers describe repository snapshots indexed by DeepWiki, not local uncommitted files.
55
57
 
56
58
  ## Implementation notes
@@ -59,4 +61,4 @@ DeepWiki's public MCP endpoint exposes exactly three operations: list a wiki's p
59
61
 
60
62
  DeepWiki may return generated explanations with source-file citations and "related pages" links. The TUI uses a local renderer (`render.ts`) rather than Pi's generic fallback, which would dump the full (often large) `content` text. Call questions, page names, and result titles are whitespace-normalized into bounded one-line summaries. Collapsed result text uses the quieter tool-output color and keeps the configured expand hint on the same logical line; expanding renders the complete response as Markdown. Historical malformed titles, requested pages, and error messages are bounded and fall back safely instead of breaking transcript rendering.
61
63
 
62
- Successful responses are cached in-process for 10 minutes, keyed by action, repo, and question. Failed, aborted, and timed-out requests are not cached. The cache stores the full response; `contents` truncation is recomputed per call, so cached and fresh calls return identical text.
64
+ Successful responses are cached in-process for 10 minutes, keyed by action, repo, and question. Caller cancellation is checked before cache lookup as well as after transport, so an already-aborted call never receives a cached result. Failed, aborted, timed-out, and oversized requests are not cached. The cache stores the transport-bounded full response; `contents` page extraction and model-facing truncation are recomputed per call, so cached and fresh calls return identical text.
@@ -4,7 +4,8 @@ Adds a `question` tool for asking one to four multiple-choice questions when the
4
4
 
5
5
  ## Behavior
6
6
 
7
- - Each option requires a concise description of its consequence or trade-off. Questions, labels, descriptions, and previews have input-length limits so the dialog stays usable.
7
+ - Each option requires a concise description of its consequence or trade-off. Questions, headers, option labels, descriptions, and provided previews must contain visible non-whitespace text and stay within their input-length limits; punctuation such as a trailing question mark is guidance, not a validation requirement.
8
+ - Question tool calls execute sequentially, so two calls in one tool batch cannot open competing blocking dialogs.
8
9
  - A single single-select question submits as soon as the user selects an option.
9
10
  - A multi-question flow advances after each single-select answer; multi-select uses `Space` to toggle choices and Enter to continue. Once every question is answered, a **Review answers** view requires explicit submission.
10
11
  - Options are numbered; pressing `1`–`9` jumps to the matching option — selecting it in single-select, toggling it in multi-select. The custom-answer row's number opens its input.
@@ -13,8 +14,9 @@ Adds a `question` tool for asking one to four multiple-choice questions when the
13
14
  - `Type something` is appended automatically for custom answers. Authored options may not use reserved labels (`Other`, `Type something`, the legacy `Type something.`, or `Chat about this`); the comparison is case-insensitive and ignores surrounding whitespace.
14
15
  - `Tab` opens a note editor for the focused option; in multi-select, the option must be selected first. In single-select it also selects the option, and cancelling the note editor with `Esc` restores the previous selection. On the custom-answer row, it opens custom-answer input.
15
16
  - Multi-select custom answers stay on the `Type something` row, are selected when saved, and can be toggled with `Space` without losing text. Enter on that row opens the input while no custom answer exists yet.
16
- - `preview` shows focused single-select content beside the choices on wide terminals and beneath them on narrow terminals. Preview height is capped and reports hidden lines. Previews on multi-select questions are rejected with a `preview_multiselect` error.
17
+ - `preview` shows focused single-select content beside the focused choice on wide terminals and directly beneath it on narrow terminals. Preview height is capped and reports hidden lines. Previews on multi-select questions are rejected with a `preview_multiselect` error.
17
18
  - The dialog is available only in TUI mode. RPC, JSON, and print calls return a structured `no_ui` error rather than attempting a custom component.
19
+ - Short terminals use a height-bounded vertical viewport. Moving option focus keeps that option and its preview visible; long Review answers can be scrolled with the configured up/down bindings while Enter still submits and Esc returns to editing.
18
20
  - Aborting the turn closes the dialog and resolves the call as cancelled with the answers given so far.
19
21
 
20
22
  ## Result contract
@@ -31,7 +33,7 @@ Adds a `question` tool for asking one to four multiple-choice questions when the
31
33
  }
32
34
  ```
33
35
 
34
- Only `content` reaches the model. Successful results are numbered, clearly identify single/custom/multi answers, retain notes, and state when a preview was selected without echoing its full source. Cancelling — via `Esc` or a turn abort — lists any answers already given as partial answers alongside the decline message. Model-facing output is capped at 12,000 characters; if it is truncated, the result instructs the model to ask a focused follow-up question. Notes and custom answers are capped at 4,000 characters in the dialog.
36
+ Only `content` reaches the model. Successful results are numbered, clearly identify single/custom/multi answers, retain notes, and state when a preview was selected without echoing its full source. Cancelling — via `Esc` or a turn abort — lists any answers already given as partial answers alongside the decline message. Model-facing output is capped at 12,000 characters; if it is truncated, the result instructs the model to ask a focused follow-up question. Notes and custom answers are capped at 4,000 characters in the dialog. Only `outcome: "error"` is mapped to Pi's protocol-level tool error flag; answered, cancelled, and clarification outcomes remain normal results.
35
37
 
36
38
  The transcript uses a private `renderCall` / `renderResult` only to replace raw question JSON and model-oriented result text with concise user summaries. The collapsed call keeps a bounded header; expanding lists every question in full and marks multi-select prompts. Cancelled and clarification outcomes report `answered N of M`, and the expanded result preserves partial decisions and notes. Human-readable validation errors are shown instead of machine codes, while older or malformed session details fall back defensively to bounded content. Schema-level argument failures show only the first bounded error (plus any remaining count) when collapsed and reveal the bounded validator report with received arguments only when expanded. Pi retains its native tool shell and pending/error state.
37
39
 
@@ -48,5 +50,5 @@ Dialog footers use configured keybindings where Pi exposes them, format compact
48
50
 
49
51
  - Uses Pi's native `ctx.ui.custom()` lifecycle; no state is shared with another extension.
50
52
  - The render cache is keyed by terminal width **and height**, because preview height depends on available rows and Pi resize only requests a render. Preview markdown rendering is additionally memoized per text and dimensions so editor keystrokes don't re-parse previews.
51
- - `validateQuestions` enforces only what the JSON schema cannot express: case-insensitive uniqueness, reserved-label rejection, and the preview/multi-select conflict. Length and count limits are enforced against the schema before the tool executes.
53
+ - `validateQuestions` defensively trims every visible text field and rejects whitespace-only content, then enforces case-insensitive uniqueness, reserved-label rejection, and the preview/multi-select conflict. The JSON schema separately carries non-empty, length, and count constraints before execution.
52
54
  - Dialog navigation follows Pi's injected select/input keybindings where applicable; compact footer labels show the first configured binding in a human-readable form. Custom actions such as Space-to-toggle remain explicit in the footer.
@@ -108,7 +108,7 @@ There is **no migration** from any older models-manager config, and Pi updates d
108
108
  ## Limits
109
109
 
110
110
  - SSE only — no Codex WebSocket or zstd-compressed request body.
111
- - Catalog probe expects OpenAI-style `{ data: [{ id }] }` response format.
111
+ - Catalog probe expects OpenAI-style `{ data: [{ id }] }` response format. Successful catalog bodies are streamed with a 4 MiB limit; oversized responses are cancelled, and non-OK response text is bounded before it is shown.
112
112
  - Empty model list → provider is not registered (nothing appears in `/model`).
113
113
  - Body is Codex-oriented for transparent gateways; auth and URL remain Platform Responses (`sk-` + `/responses`).
114
114
  - Replayed optional top-level `ResponseItem.id` identity fields are omitted from stateless requests, matching Codex CLI 0.145's default `store: false` wire behavior. Required semantic references such as `item_reference.id`, plus `call_id` and encrypted reasoning content, remain intact.
@@ -40,6 +40,7 @@ CTX 2.1%/1.0M ↑13k ↓13k R440k CH99.4% $0.074
40
40
  - `↓` cumulative output tokens.
41
41
  - `R` cumulative cache-read tokens.
42
42
  - `W` cumulative cache-write tokens, omitted when zero.
43
+ - Cumulative totals include assistant requests, usage-bearing tool results, compaction summaries, and branch summaries on the active branch.
43
44
  - `CH` cache-hit percentage for the latest assistant request, calculated as
44
45
  `cacheRead / (input + cacheRead + cacheWrite)` and shown only when that
45
46
  request used cache.
@@ -39,7 +39,7 @@ There are exactly two profiles:
39
39
  - **Explorer** (`explorer`, default): read-only investigation with `read`, `grep`, `find`, `ls`, and `bash`. Bash remains available for Git history and inspection commands such as `git log`, `git diff`, `git blame`, `git show`, `git status`, `wc`, `head`, and `tail`. Its system prompt forbids redirects, heredoc writes, temporary files, state-changing Git commands, installs, and network access.
40
40
  - **General** (`general`): implementation, file changes, and stateful verification with `read`, `bash`, `edit`, and `write`.
41
41
 
42
- There are no user or project profile files. Child sessions load no extensions, skills, prompt templates, or themes, so workers cannot recursively call `subagent` or inherit unrelated extension capabilities. Explorer continues to skip project context files such as `AGENTS.md`; General loads trusted project context normally.
42
+ There are no user or project profile files. Child sessions load no extensions, skills, prompt templates, or themes, so workers cannot recursively call `subagent` or inherit unrelated extension capabilities. Both profiles load the applicable repository instructions for their working directory, including layered `AGENTS.md` or `CLAUDE.md` files. Explorer's tool set and system prompt remain strictly read-only.
43
43
 
44
44
  Worker contexts are isolated, but workers share the parent's checkout. Concurrent tasks therefore must be independent and must not perform overlapping writes.
45
45
 
@@ -67,13 +67,13 @@ Overrides are saved atomically in:
67
67
  ~/.pi/agent/subagent.json
68
68
  ```
69
69
 
70
- Only `explorer` and `general` keys are valid. A stale or invalid `subagent.json` (older formats, unknown profiles, or malformed JSON) is reset to an empty, fully inheriting config the first time it is loaded, so an old file never blocks the tool or `/agents`. Overrides affect future workers and never change the parent session's model or thinking level.
70
+ Only `explorer` and `general` keys are valid. A malformed, unsupported, unreadable, or future-version `subagent.json` is never rewritten during load: workers temporarily inherit the parent settings and the UI reports the problem. On the first actual settings change, Pi backs up the original bytes to a collision-safe `.invalid-<timestamp>-<pid>.bak` file before writing a valid replacement; if the backup fails, the save is cancelled. Concurrent Pi processes lock, re-read, and merge profile changes before an atomic write, and no-op changes leave the file and its timestamp untouched. Overrides affect future workers and never change the parent session's model or thinking level.
71
71
 
72
72
  ## Lifecycle and retry
73
73
 
74
74
  - The parent call waits until every worker reaches a terminal state.
75
75
  - Parent abort, `/reload`, `/new`, `/resume`, `/fork`, and session shutdown abort active and queued workers.
76
- - Provider auto-retry remains visible as `Retrying (n/m) in Xs`.
76
+ - Provider auto-retry remains visible under the expanded task Outcome as `Retrying (n/m) in Xs`.
77
77
  - A retryable failure that produced no turns or tool use may be retried at task level up to two more times. Runs with partial work are never restarted.
78
78
  - Retry backoff does not hold a concurrency slot; another queued worker can run while the failed task waits.
79
79
  - A parent abort or session shutdown interrupts queued and retrying workers immediately.
@@ -82,56 +82,46 @@ Child sessions share the parent's canonical model/authentication runtime, so ext
82
82
 
83
83
  ## Transcript UI
84
84
 
85
- The native tool title owns whole-call elapsed time. While running, the collapsed view lists one width-bounded physical row per task:
85
+ Pi's native tool chrome owns the aggregate `● Subagent` call marker and the dim continuation rail. The collapsed view is a compact flow containing one cell per task:
86
86
 
87
87
  ```text
88
- ● Subagent · 12s
89
- │ › #1 Explorer · Thinking...
90
- │ › #2 Explorer · Run git log
91
- │ ○ #3 Explorer · Queued
92
- │ › #4 General · Compacting...
88
+ ● Subagent
89
+ │ ✼ #1 Explorer · ○ #2 Explorer · ✓ #3 General · × #4 General
93
90
  ```
94
91
 
95
- `#N` is the task's stable one-based input position. Rows always remain in `#1` through `#N` order: there is no progress header, prompt excerpt, row cap, active-first reordering, or `+N more` truncation. A row reports the task's current state directly:
92
+ `#N` is the task's stable one-based input position. Cells always remain in `#1` through `#N` order and contain only the task marker, ordinal, and profile. Running cells use the breathing dot-to-star bloom, queued cells use `○`, and completed, failed, or aborted cells use `✓`, `×`, or `■`. Wide batches wrap at cell boundaries with uniform columns. If the terminal is narrower than one complete cell, every task receives its own width-truncated row so all ordinals remain visible. Collapsed cards never expose prompts, activities, timings, token totals, costs, or failure text. Live repainting runs at 120ms only for visible collapsed blooms and at one second for expanded running durations or retry countdowns; queued, static, settled, and disposed rows keep no refresh timer.
96
93
 
97
- - `Starting...` before the worker has begun a turn;
98
- - `Thinking...` while the model is active without a tool;
99
- - `Read`, `Search`, `Find`, `List`, `Run`, `Edit`, or `Write` for the current tool;
100
- - `Compacting...` during worker auto-compaction;
101
- - `Queued` while waiting for a worker slot;
102
- - `Retrying (n/m) in Xs` during retry backoff;
103
- - `Completed`, `Failed`, or `Aborted`, with duration when the task started.
104
-
105
- Long states and activities are truncated by visible terminal width, including ANSI styling and wide CJK characters, instead of wrapping onto continuation rows.
106
-
107
- Once settled, aggregate cost joins the frozen duration in the native title, and the ordered task rows become the complete collapsed outcome summary:
94
+ Expanding removes aggregate Batch chrome and gives every task the same four-part layout:
108
95
 
109
96
  ```text
110
- ● Subagent · 1m 24s · $0.042
111
- │ ✓ #1 Explorer · Completed · 48s
112
- │ ✓ #2 Explorer · Completed · 1m 3s
113
- │ × #3 General · Failed · 36s
114
- │ ✓ #4 Explorer · Completed · 1m 20s
97
+ ● Subagent
98
+ │ #1 Explorer · anthropic/claude-opus-5 · max · 99.9k tok · 60 tool calls · 12m 47s
99
+ │
100
+ │ Prompt
101
+ │ Inspect the renderer and report the exact data flow.
102
+ │
103
+ │ Activity · last 3 of 60 tool calls
104
+ │ Read(src/extensions/subagent/render.ts)
105
+ │ Grep(src/extensions/subagent)
106
+ │ Run(npm test -- test/subagent-render.test.ts)
107
+ │
108
+ │ Outcome
109
+ │ Still running...
115
110
  ```
116
111
 
117
- Zero cost is omitted. There is no separate aggregate count line; the per-task markers show the mixed outcome directly.
112
+ The single-line task header always shows the profile, exact `provider/model` ID, raw thinking level (including `off`), cumulative provider-reported token usage, tool-call count, and task duration. Tokens use compact `k`/`M` notation with at most one decimal. The header omits working directory, turns, per-run cost, and aggregate Batch timing or cost, and truncates rather than wraps when the terminal is narrow.
118
113
 
119
- Expanded sections also remain in input order. Their single-line header contains only identity and compact runtime metadata:
114
+ Prompt contains the complete original task briefing and remains visible in every state. Prompt, Activity, and Outcome bodies use a two-column inset under their section labels.
120
115
 
121
- ```text
122
- ── #1 Explorer · anthropic/claude-sonnet-4-5 · medium · 3 tool uses · 2 turns · 1m 5s
116
+ Activity retains only the latest three actual tool calls, in execution order. Its denominator is the run's total tool-call count; small histories use `Activity · N tool calls`, and an empty history says `No tool calls yet.` Calls use compact `Read(path)`, `Grep(path)`, `Find(pattern)`, `List(path)`, `Run(command)`, `Edit(path)`, or `Write(path)` presentation. Synthetic compaction entries do not increment or occupy the tool-call history.
123
117
 
124
- Prompt
125
- <complete original task briefing>
126
-
127
- Activity
128
- Read .github/workflows/ci.yml
129
- › Run npm test
130
- ```
118
+ Outcome stays in the same position throughout the task lifecycle:
131
119
 
132
- The thinking level is shown as its raw value (`medium`, not `medium thinking`) and omitted when it is `off`; a non-parent working directory appears as `cwd: ...`. Per-run token, context, and cost fields are omitted from this header.
120
+ - queued or running: `Still running...`, followed by a retry countdown or active compaction state when applicable;
121
+ - completed: the worker's final Markdown report, or `No outcome returned.`;
122
+ - failed or aborted: the terminal reason, followed by `Partial outcome:` and the bounded report when useful output survived.
133
123
 
134
- Every expanded task shows the complete original Prompt, including while the batch is still running. Active and queued tasks show bounded Activity history and retry state. A completed, failed, or aborted task immediately switches to Error/Report presentation even if sibling tasks are still active; failed or aborted workers with useful output use `Report · partial`. Streaming assistant text is not copied into the parent transcript.
124
+ A terminal task exposes its Outcome immediately even while sibling tasks remain active. Profile identity, section headings, activity states, and outcomes use semantic theme colors; report Markdown keeps its normal Markdown palette instead of inheriting a blanket success or error color.
135
125
 
136
126
  Full child transcripts are not stored separately. Activity, errors, reports, usage, and model-facing output remain bounded, and completed calls restore through the parent session tree.
137
127
 
@@ -19,7 +19,7 @@ The MiniMax CN account (`minimax-cn`) is preferred over the global one (`minimax
19
19
 
20
20
  Configure with `/login minimax-cn` or `/login deepseek`, or by exporting the environment variables above.
21
21
 
22
- When no key is configured, `web_search` is removed from the model's tool set and system prompt entirely — the model never sees or calls it. This is re-evaluated on every session start (`startup`, `/new`, `/reload`, resume, fork), so a mid-session `/login` takes effect from the next session onward. The tool stays registered: it remains listed in `/tools` (where it can be force-enabled, in which case calls fail with the disabled message), and historical sessions render normally.
22
+ When no key is configured, `web_search` is removed from the model's tool set and system prompt entirely — the model never sees or calls it. This is re-evaluated on every session start (`startup`, `/new`, `/reload`, resume, fork). When credentials are available, the extension leaves the host's active-tool set unchanged: normal registration keeps the tool available by default, while an explicit `/tools` or SDK-host disable remains respected until that host enables it again. The tool always stays registered for `/tools` and historical rendering; force-enabling it without keys returns the disabled message.
23
23
 
24
24
  ## Usage
25
25
 
@@ -34,9 +34,9 @@ The model-facing payload is Markdown containing up to 12 HTTP(S) source results.
34
34
  ## Limits
35
35
 
36
36
  - With no configured key the tool is hidden from the model (see Credentials); the disabled message only appears when the tool was force-enabled via `/tools` without keys.
37
- - Engine failures are independent: if one engine errors, the other's results are still returned; the tool errors only when every configured engine fails.
37
+ - Engine failures are independent: if one engine errors, the other's results are still returned; the tool errors only when every configured engine fails. Error outcomes are marked as protocol-level tool errors; the credential-disabled warning is not.
38
38
  - MiniMax search uses the Coding Plan Search endpoint (`POST /v1/coding_plan/search`), which requires a Coding Plan key — a standard MiniMax API key may be rejected upstream.
39
- - DeepSeek search goes through the Anthropic-compatible endpoint (`/anthropic/v1/messages`, model `claude-sonnet-search`) with the server-side `web_search_20250305` tool; the request uses `max_tokens: 1024`, followed by the local output bound above.
39
+ - DeepSeek search goes through the Anthropic-compatible endpoint (`/anthropic/v1/messages`, model `claude-sonnet-search`) with the server-side `web_search_20250305` tool; the request uses `max_tokens: 1024`, followed by the local output bound above. A response must contain a structured `web_search_tool_result`: an empty result array is a valid zero-result search, while text-only, malformed, or structured-error responses count as a provider failure and their synthesis is discarded.
40
40
  - Requests time out after 60 seconds (MiniMax) or 90 seconds (DeepSeek) and surface as Pi tool errors. Successful upstream response bodies are limited to 2 MiB, error bodies to 200 bytes, and model-facing error messages to 500 characters.
41
41
 
42
42
  ## Implementation notes
@@ -6,8 +6,9 @@ This repository is the standalone distribution of `@astralyn/pi`. It publishes o
6
6
 
7
7
  - Node.js `>=22.19`
8
8
  - npm
9
+ - `fd` (or `fdfind`) and `rg` for the complete test suite; Pi-managed copies are reused when available
9
10
 
10
- The package consumes the published `@earendil-works/pi-ai`, `@earendil-works/pi-agent-core`, and `@earendil-works/pi-tui` dependencies. It does not recreate the upstream monorepo or vendor those packages.
11
+ The package consumes the published `@earendil-works/pi-ai`, `@earendil-works/pi-agent-core`, `@earendil-works/pi-client`, `@earendil-works/pi-protocol`, and `@earendil-works/pi-tui` dependencies. It does not recreate the upstream monorepo or vendor those packages.
11
12
 
12
13
  ## Install and run
13
14
 
@@ -59,12 +60,16 @@ Run all tests in an isolated home and configuration directory:
59
60
  npm run test:isolated
60
61
  ```
61
62
 
62
- Validate the exact upstream release baseline and local deviations:
63
+ The runner keeps credentials and settings isolated, prepends the real Pi managed-bin when present, and preflights `fd`/`fdfind` plus `rg` before starting Vitest.
64
+
65
+ Validate the exact upstream release baseline, all five upstream runtime dependencies, and local deviations:
63
66
 
64
67
  ```bash
65
68
  npm run diff:upstream -- --check
66
69
  ```
67
70
 
71
+ Ordinary CI fetches the recorded release tag and runs this gate before build and tests.
72
+
68
73
  For interactive changes, also test in a real TTY, including pending and settled tool output, collapsed and expanded states, and relevant `/reload` or `/tree` flows.
69
74
 
70
75
  ## Repository layout
@@ -2294,7 +2294,7 @@ By default, tool output is wrapped in Pi's native call/result shell, which owns
2294
2294
 
2295
2295
  Set `renderShell: "self"` when the tool should render its own shell instead of using the native shell. This is useful for tools that need complete control over framing or background behavior, for example large previews that must stay visually stable after the tool settles.
2296
2296
 
2297
- For live progress UI (elapsed time, retry countdowns), schedule repaints from the renderer itself: store a timer handle in `context.state`, arm a `setTimeout` that calls `context.invalidate()` while `options.isPartial` is true, and clear it on the first settled render. `context.invalidate()` is a no-op after the row is disposed, so a trailing timeout is harmless.
2297
+ For live progress UI (elapsed time, retry countdowns), schedule repaints from the renderer itself: store a timer handle in `context.state`, arm a `setTimeout` that calls `context.invalidate()` only while the current view contains changing text, and clear it on the first static or settled render. Set `context.state.dispose` to the same idempotent cleanup function when a timer may still be armed; the shell invokes it when the row is disposed.
2298
2298
 
2299
2299
  Derive displayed time from an absolute timestamp or deadline (`Date.now()`), not by decrementing a counter on every refresh. A refresh is only a repaint opportunity; event-loop stalls and machine sleep must not extend a wall-clock timeout.
2300
2300
 
@@ -2316,7 +2316,7 @@ pi.registerTool({
2316
2316
 
2317
2317
  `renderCall` and `renderResult` each receive a `context` object with:
2318
2318
  - `args` - the current tool call arguments
2319
- - `state` - shared row-local state across `renderCall` and `renderResult`
2319
+ - `state` - shared row-local state across `renderCall` and `renderResult`; an optional `dispose()` cleanup is called when the row is disposed
2320
2320
  - `lastComponent` - the previously returned component for that slot, if any
2321
2321
  - `invalidate()` - request a rerender of this tool row
2322
2322
  - `toolCallId`, `cwd`, `executionStarted`, `argsComplete`, `isPartial`, `expanded`, `showImages`, `isError`
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@astralyn/pi",
3
- "version": "0.84.14",
3
+ "version": "0.84.15",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@astralyn/pi",
9
- "version": "0.84.14",
9
+ "version": "0.84.15",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@earendil-works/pi-agent-core": "0.84.4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astralyn/pi",
3
- "version": "0.84.14",
3
+ "version": "0.84.15",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {