@kingingwang/pi-windows-x64 0.84.0 → 0.84.2

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 (34) hide show
  1. package/bin/CHANGELOG.md +94 -1
  2. package/bin/README.md +1 -0
  3. package/bin/docs/compaction.md +6 -6
  4. package/bin/docs/custom-provider.md +1 -1
  5. package/bin/docs/environment-variables.md +8 -2
  6. package/bin/docs/extensions.md +7 -2
  7. package/bin/docs/json.md +6 -4
  8. package/bin/docs/keybindings.md +16 -6
  9. package/bin/docs/providers.md +8 -1
  10. package/bin/docs/rpc.md +15 -4
  11. package/bin/docs/sdk.md +9 -0
  12. package/bin/docs/settings.md +32 -0
  13. package/bin/docs/terminal-setup.md +23 -2
  14. package/bin/docs/themes.md +24 -3
  15. package/bin/docs/tui.md +2 -2
  16. package/bin/docs/usage.md +3 -2
  17. package/bin/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  18. package/bin/examples/extensions/custom-provider-anthropic/package.json +1 -1
  19. package/bin/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  20. package/bin/examples/extensions/gondolin/package-lock.json +2 -2
  21. package/bin/examples/extensions/gondolin/package.json +1 -1
  22. package/bin/examples/extensions/sandbox/package-lock.json +2 -2
  23. package/bin/examples/extensions/sandbox/package.json +1 -1
  24. package/bin/examples/extensions/subagent/README.md +2 -0
  25. package/bin/examples/extensions/subagent/agents.ts +40 -9
  26. package/bin/examples/extensions/subagent/index.ts +21 -3
  27. package/bin/examples/extensions/with-deps/package-lock.json +2 -2
  28. package/bin/examples/extensions/with-deps/package.json +1 -1
  29. package/bin/package.json +7 -7
  30. package/bin/pi.exe +0 -0
  31. package/bin/theme/dark.json +2 -0
  32. package/bin/theme/light.json +2 -0
  33. package/bin/theme/theme-schema.json +9 -1
  34. package/package.json +1 -1
package/bin/CHANGELOG.md CHANGED
@@ -1,10 +1,103 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.84.2] - 2026-08-14
4
+
5
+ ### New Features
6
+
7
+ - **Fullscreen transcript search** — Search and navigate matches in fullscreen mode. See [TUI Fullscreen Viewport](docs/keybindings.md#tui-fullscreen-viewport).
8
+ - **Configurable default tools** — Choose startup built-in tools globally or per project. See [Tools](docs/settings.md#tools).
9
+ - **Configurable fullscreen exit output** — Print the transcript or only a resume hint on exit. See [Interactive Mode](docs/usage.md#interactive-mode).
10
+
11
+ ### Added
12
+
13
+ - Added fullscreen transcript search with `Ctrl+Shift+F`, incremental match highlighting, configurable search match theme colors, and next/previous navigation with `Enter`/`Ctrl+G` and `Shift+Enter`/`Ctrl+Shift+G`.
14
+ - Added experimental strict JSON-schema constrained sampling for the default `read`, `bash`, `edit`, and `write` tools under `PI_EXPERIMENTAL=1`.
15
+ - Added a fullscreen exit output setting to choose between printing the final transcript and only a session resume hint.
16
+ - Added the `defaultTools` setting for configuring the initial built-in tool selection globally or per project.
17
+ - Added `--use-theme <name[/name]>` to choose an initial per-run interactive theme without changing saved settings ([#7722](https://github.com/earendil-works/pi/pull/7722) by [@rwachtler](https://github.com/rwachtler)).
18
+ - Added `expandPromptTemplates` to extension `pi.sendUserMessage()` options for explicitly dispatching commands and expanding skills and prompt templates. See [`pi.sendUserMessage()`](docs/extensions.md#pisendusermessagecontent-options) ([#7857](https://github.com/earendil-works/pi/pull/7857) by [@mrexodia](https://github.com/mrexodia)).
19
+ - Added inherited `createGatewayBindingFetch()` for routing Cloudflare AI Gateway requests through a Workers AI binding without an API token ([#7901](https://github.com/earendil-works/pi/pull/7901) by [@Maximo-Guk](https://github.com/Maximo-Guk)).
20
+ - Added inherited `AssistantMessage.endTurn` to preserve OpenAI Codex's terminal `end_turn` signal for diagnostics ([#7766](https://github.com/earendil-works/pi/pull/7766)).
21
+ - Added inherited unbound single-line transcript scrolling actions for fullscreen mode. See [TUI Fullscreen Viewport](docs/keybindings.md#tui-fullscreen-viewport) ([#7903](https://github.com/earendil-works/pi/pull/7903) by [@midastruth](https://github.com/midastruth)).
22
+
23
+ ### Changed
24
+
25
+ - Changed inherited Kimi Coding requests to use pi's runtime `User-Agent` header.
26
+ - Replaced the inherited Mistral SDK transport with a native Chat Completions HTTP stream, eliminating its generated client and schema runtime overhead.
27
+ - Documented the generic `AI_AGENT=pi` process marker and how it differs from `PI_CODING_AGENT=true` ([#7747](https://github.com/earendil-works/pi/issues/7747)).
28
+ - Changed inherited OpenAI Responses deferred tool loading to prefer message-anchored `additional_tools` where supported while retaining tool-search and top-level fallbacks ([#7709](https://github.com/earendil-works/pi/issues/7709)).
29
+ - Reduced inherited fullscreen rendering allocation churn by painting full-width layout rows directly instead of recompositing them on every frame.
30
+
31
+ ### Fixed
32
+
33
+ - Fixed managed-tool downloads delaying TUI startup and hiding diagnostics in fullscreen mode by mounting the TUI first and showing download progress and warnings inside it.
34
+ - Fixed opening a model selector immediately after startup cancelling and restarting the in-progress model catalog refresh.
35
+ - Fixed inherited GitHub Copilot login triggering API rate limits while enabling model policies by limiting concurrent policy updates ([#6187](https://github.com/earendil-works/pi/issues/6187)).
36
+ - Fixed fullscreen transcript search snapping back to the current match during manual scrolling and fragmented mouse input leaking into the search query.
37
+ - Fixed inherited required LaTeX arguments starting on a new line being parsed as empty ([#7760](https://github.com/earendil-works/pi/issues/7760)).
38
+ - Updated the transitive `nanoid` development dependency to address a denial-of-service vulnerability.
39
+ - Fixed fallback rendering for extension tool results to collapse long output and honor tool expansion ([#7979](https://github.com/earendil-works/pi/issues/7979)).
40
+ - Fixed JSON and RPC `message_update` events dropping cumulative usage during streaming. See [JSON Event Mode](docs/json.md) and [RPC `message_update`](docs/rpc.md#message_update-streaming) ([#7982](https://github.com/earendil-works/pi/pull/7982) by [@christianklotz](https://github.com/christianklotz)).
41
+ - Fixed `pi.sendMessage(..., { triggerTurn: false })` steering an active run instead of only recording the custom message ([#8022](https://github.com/earendil-works/pi/pull/8022) by [@cristinaponcela](https://github.com/cristinaponcela)).
42
+ - Fixed the `defaultTools` setting dropping extension and SDK custom tools when selecting built-in defaults.
43
+ - Fixed the subagent example rejecting YAML array syntax for the `tools` frontmatter field ([#7598](https://github.com/earendil-works/pi/pull/7598) by [@alexsavio](https://github.com/alexsavio)).
44
+ - Fixed the subagent example dropping parent session model, thinking, and tool configuration ([#7897](https://github.com/earendil-works/pi/pull/7897) by [@virtuald](https://github.com/virtuald)).
45
+ - Fixed custom system prompts concatenating the current working directory with later appended prompt content ([#7887](https://github.com/earendil-works/pi/pull/7887) by [@distributedlock](https://github.com/distributedlock)).
46
+ - Fixed inherited OpenAI Responses function and custom tool calls losing namespaces during streaming, proxying, and replay ([#7709](https://github.com/earendil-works/pi/issues/7709)).
47
+ - Fixed inherited upstream request buffer failures not triggering automatic assistant retries.
48
+ - Fixed inherited built-in and custom DeepSeek API models sending output limits through an unsupported field.
49
+ - Fixed inherited Amazon Bedrock replay rejecting tool arguments that contain empty object keys while preserving all valid nested values ([#7882](https://github.com/earendil-works/pi/pull/7882) by [@muyiyr](https://github.com/muyiyr)).
50
+ - Fixed inherited DeepSeek compatibility detection for base URLs whose hostname contains uppercase letters ([#7933](https://github.com/earendil-works/pi/pull/7933) by [@yearth](https://github.com/yearth)).
51
+ - Fixed inherited Google Generative AI and Vertex AI responses with tool calls incorrectly treating output-limit or provider-error stops as normal tool use ([#8059](https://github.com/earendil-works/pi/issues/8059)).
52
+ - Fixed inherited fullscreen mouse drag selection and OSC 8 link activation in terminals that report generic SGR mouse release button codes ([#7963](https://github.com/earendil-works/pi/issues/7963)).
53
+ - Fixed inherited focused fullscreen overlays not receiving mouse wheel or viewport scroll keys such as PageUp and PageDown ([#7894](https://github.com/earendil-works/pi/issues/7894)).
54
+ - Fixed inherited LaTeX control spaces split across line endings causing complete expressions to fall back to raw source.
55
+ - Fixed split `Alt+Enter` input over SSH being misread as Escape, added `PI_TUI_ESC_TIMEOUT` for high-latency terminals, and limited that timeout to lone Escape input ([#7899](https://github.com/earendil-works/pi/pull/7899) by [@powerfooI](https://github.com/powerfooI)).
56
+ - Fixed inherited idle fullscreen sessions repainting and clearing text selection when the terminal loses focus ([#7892](https://github.com/earendil-works/pi/pull/7892) by [@terrorobe](https://github.com/terrorobe)).
57
+ - Fixed fullscreen selection copy to use the host clipboard and report failure instead of claiming success when OSC 52 is unsupported ([#8110](https://github.com/earendil-works/pi/pull/8110) by [@Panoplos](https://github.com/Panoplos)).
58
+
59
+ ## [0.84.1] - 2026-08-07
60
+
61
+ ### New Features
62
+
63
+ - **Qwen Token Plan Individual** — Use the built-in provider for models documented for Individual subscriptions. See [API Keys](docs/providers.md#api-keys).
64
+ - **Authentication readiness checks** — Use `pi auth check` to verify provider or model credentials, optionally emitting the resolved credential.
65
+ - **Improved fullscreen interaction** — Select words and paragraphs with multiple clicks and configure half-page transcript scrolling. See [TUI Fullscreen Viewport](docs/keybindings.md#tui-fullscreen-viewport).
66
+ - **Terminating blocked tool calls** — Extension `tool_call` handlers can stop all-terminating batches without another model call. See [Tool Events](docs/extensions.md#tool-events).
67
+
68
+ ### Added
69
+
70
+ - Added Qwen Token Plan Individual as a built-in provider with its documented subscription model catalog and the shared international `QWEN_TOKEN_PLAN_API_KEY`. See [API Keys](docs/providers.md#api-keys) ([#7659](https://github.com/earendil-works/pi/pull/7659) by [@arasovic](https://github.com/arasovic)).
71
+ - Added `pi auth check` provider/model auth preflight with optional credential output ([#7152](https://github.com/earendil-works/pi/issues/7152)).
72
+ - Added `terminate` support to blocked extension `tool_call` events so all-terminating batches can skip the automatic follow-up model call. See [Tool Events](docs/extensions.md#tool-events) ([#7715](https://github.com/earendil-works/pi/pull/7715) by [@muyiyr](https://github.com/muyiyr)).
73
+ - Added inherited double-click word and whitespace selection, granularity-aware drag selection, and triple-click paragraph selection in fullscreen mode ([#7725](https://github.com/earendil-works/pi/issues/7725), [#7733](https://github.com/earendil-works/pi/pull/7733) by [@volsa](https://github.com/volsa)).
74
+ - Added inherited unbound half-page transcript scrolling actions for fullscreen mode. See [TUI Fullscreen Viewport](docs/keybindings.md#tui-fullscreen-viewport) ([#7735](https://github.com/earendil-works/pi/issues/7735)).
75
+
76
+ ### Changed
77
+
78
+ - Softened the bash tool's `PI_*` environment guideline in an attempt to reduce unnecessary inspection commands ([#7128](https://github.com/earendil-works/pi/issues/7128)).
79
+ - Reduced worst-case automatic terminal theme detection delay from 200 ms to 100 ms by probing color-scheme and background support concurrently.
80
+
81
+ ### Fixed
82
+
83
+ - Fixed Bun standalone binaries crashing on startup when the cwd contains a `bunfig.toml` with `preload` by compiling with `--no-compile-autoload-bunfig` ([#7685](https://github.com/earendil-works/pi/pull/7685) by [@geril07](https://github.com/geril07)).
84
+ - Fixed extension TUI method wrappers recursing indefinitely when delegating to the original method ([#7731](https://github.com/earendil-works/pi/issues/7731)).
85
+ - Fixed right-click not pasting clipboard text in fullscreen mode on Windows.
86
+ - Fixed inherited `Agent.reset()` clearing transcript and runtime state during active runs; it now rejects until the agent is idle ([#7717](https://github.com/earendil-works/pi/pull/7717) by [@wesleyzhangwq](https://github.com/wesleyzhangwq)).
87
+ - Fixed inherited LaTeX relation, multiplication, and named-operator spacing, and matrix composition with stacked fractions, operator limits, and adjacent matrices.
88
+ - Reduced inherited fullscreen mouse event volume under tmux, Zellij, and GNU Screen by using button-motion tracking instead of all-motion tracking.
89
+
90
+ ## [Unreleased]
91
+
92
+ ### Added
93
+
94
+ - Added a `nonStreaming` setting, `--non-streaming` CLI flag, SDK session option, prompt option, and RPC prompt field for non-streaming `openai-completions` requests.
95
+
3
96
  ## [0.84.0] - 2026-08-06
4
97
 
5
98
  ### New Features
6
99
 
7
- - **Fullscreen TUI mode** — Switch between regular and fullscreen modes at runtime, with a sticky editor and footer, independently scrollable transcript, and draggable scrollbars. See [UI & Display](docs/settings.md#ui--display).
100
+ - **Fullscreen TUI mode** — Switch between regular and fullscreen modes at runtime, with a sticky editor and footer, independently scrollable transcript, and draggable scrollbars. See [UI & Display](docs/settings.md#ui-display).
8
101
  - **Mermaid and LaTeX rendering** — Render Mermaid diagrams and terminal-friendly Unicode math in interactive transcripts. See [Markdown settings](docs/settings.md#markdown) and [TUI Markdown](../tui/README.md#markdown).
9
102
  - **Per-directory context overrides** — Use `AGENTS.override.md` to replace context files for a specific directory. See [Context Files](docs/usage.md#context-files).
10
103
  - **Advanced custom model sampling** — Configure arbitrary OpenAI-compatible `samplingParams` and opt-in vLLM `thinking_token_budget` values. See [Sampling Parameters](docs/models.md#sampling-parameters).
package/bin/README.md CHANGED
@@ -609,6 +609,7 @@ Combine `--no-*` with explicit flags to load exactly what you need, ignoring set
609
609
  | `--system-prompt <text>` | Replace default prompt (context files and skills still appended) |
610
610
  | `--append-system-prompt <text>` | Append to system prompt |
611
611
  | `--tui-mode <mode>` | TUI mode: `regular` (default) or experimental `fullscreen` |
612
+ | `--use-theme <name[/name]>` | Set the initial interactive theme for this run without changing settings |
612
613
  | `--verbose` | Force verbose startup |
613
614
  | `-a`, `--approve` | Trust project-local files for this run |
614
615
  | `-na`, `--no-approve` | Ignore project-local files for this run |
@@ -1,6 +1,6 @@
1
1
  # Compaction & Branch Summarization
2
2
 
3
- LLMs have limited context windows. When conversations grow too long, pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
3
+ LLMs have limited context windows. When conversations grow too long, Pi uses compaction to summarize older content while preserving recent work. This page covers both auto-compaction and branch summarization.
4
4
 
5
5
  **Source files** ([pi-mono](https://github.com/earendil-works/pi-mono)):
6
6
  - [`packages/coding-agent/src/core/compaction/compaction.ts`](https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/src/core/compaction/compaction.ts) - Auto-compaction logic
@@ -42,13 +42,13 @@ You can also trigger manually with `/compact [instructions]`, where optional ins
42
42
  2. **Extract messages**: Collect messages from the previous kept boundary (or session start) up to the cut point
43
43
  3. **Generate summary**: Call LLM to summarize with structured format, passing the previous summary as iterative context when present
44
44
  4. **Append entry**: Save `CompactionEntry` with summary and `firstKeptEntryId`
45
- 5. **Reload**: Session reloads, using summary + messages from `firstKeptEntryId` onwards
45
+ 5. **Rebuilds context**: Session rebuilds the context for the next request, using summary + messages from `firstKeptEntryId` onwards
46
46
 
47
47
  ```
48
48
  Before compaction:
49
49
 
50
50
  entry: 0 1 2 3 4 5 6 7 8 9
51
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┐
51
+ ┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
52
52
  │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│
53
53
  └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┘
54
54
  └────────┬───────┘ └──────────────┬──────────────┘
@@ -59,7 +59,7 @@ Before compaction:
59
59
  After compaction (new entry appended):
60
60
 
61
61
  entry: 0 1 2 3 4 5 6 7 8 9 10
62
- ┌─────┬─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┐
62
+ ┌─────┬─────┬─────┬──────┬─────┬─────┬──────┬──────┬─────┬─────┬─────┐
63
63
  │ hdr │ usr │ ass │ tool │ usr │ ass │ tool │ tool │ ass │ tool│ cmp │
64
64
  └─────┴─────┴─────┴──────┴─────┴─────┴──────┴──────┴─────┴─────┴─────┘
65
65
  └──────────┬──────┘ └──────────────────────┬───────────────────┘
@@ -102,7 +102,7 @@ Split turn (one huge turn exceeds budget):
102
102
  turnPrefixMessages = [usr, ass, tool, ass, tool, tool]
103
103
  ```
104
104
 
105
- For split turns, pi generates two summaries and merges them:
105
+ For split turns, Pi generates two summaries and merges them:
106
106
  1. **History summary**: Previous context (if any)
107
107
  2. **Turn prefix summary**: The early part of the split turn
108
108
 
@@ -149,7 +149,7 @@ See [`prepareCompaction()`](https://github.com/earendil-works/pi-mono/blob/main/
149
149
 
150
150
  ### When It Triggers
151
151
 
152
- When you use `/tree` to navigate to a different branch, pi offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
152
+ When you use `/tree` to navigate to a different branch, Pi offers to summarize the work you're leaving. This injects context from the left branch into the new branch.
153
153
 
154
154
  ### How It Works
155
155
 
@@ -227,7 +227,7 @@ The `api` field determines which streaming implementation is used:
227
227
  | `openai-responses` | OpenAI Responses API |
228
228
  | `azure-openai-responses` | Azure OpenAI Responses API |
229
229
  | `openai-codex-responses` | OpenAI Codex Responses API |
230
- | `mistral-conversations` | Mistral SDK Conversations/Chat streaming |
230
+ | `mistral-conversations` | Native Mistral Chat Completions streaming |
231
231
  | `google-generative-ai` | Google Generative AI API |
232
232
  | `google-vertex` | Google Vertex AI API |
233
233
  | `bedrock-converse-stream` | Amazon Bedrock Converse API |
@@ -3,14 +3,19 @@
3
3
  Pi uses environment variables in three ways:
4
4
 
5
5
  - Variables such as `PI_OFFLINE` configure the Pi process.
6
- - Pi sets `PI_CODING_AGENT` so child processes can detect that they run inside Pi.
6
+ - Pi sets process markers so child processes can identify Pi as the launching agent.
7
7
  - Commands run by the LLM-callable bash tool receive `PI_*` variables describing the current session.
8
8
 
9
9
  Provider API-key variables are documented separately in [Providers](providers.md#environment-variables-or-auth-file).
10
10
 
11
11
  ## Process Marker
12
12
 
13
- The CLI and RPC entry points set `PI_CODING_AGENT=true`. Child processes inherit it and can use it to detect that they run inside Pi. It is not session-specific and is not set automatically when Pi is embedded through the SDK.
13
+ The CLI and RPC entry points set two process markers:
14
+
15
+ - `AI_AGENT=pi` is a generic marker that lets tooling identify Pi as the agent that launched the process.
16
+ - `PI_CODING_AGENT=true` is Pi-specific and lets child processes detect that they run inside Pi.
17
+
18
+ Child processes inherit both markers. They are not session-specific and are not set automatically when Pi is embedded through the SDK.
14
19
 
15
20
  ## Bash Tool Session Environment
16
21
 
@@ -82,6 +87,7 @@ These variables are read by Pi itself:
82
87
  | `PI_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
83
88
  | `PI_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
84
89
  | `PI_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
90
+ | `PI_TUI_ESC_TIMEOUT` | How long to wait after a lone ESC before treating it as Escape, in milliseconds; defaults to `100` over SSH and `10` otherwise. Increase if Alt-key input is misread as Escape |
85
91
  | `VISUAL`, `EDITOR` | External editor fallback when `externalEditor` is unset |
86
92
  | `HTTP_PROXY`, `HTTPS_PROXY` | Proxy outbound HTTP requests |
87
93
 
@@ -762,7 +762,8 @@ Behavior guarantees:
762
762
  - Mutations to `event.input` affect the actual tool execution
763
763
  - Later `tool_call` handlers see mutations made by earlier handlers
764
764
  - No re-validation is performed after your mutation
765
- - Return values from `tool_call` only control blocking via `{ block: true, reason?: string }`
765
+ - Return values from `tool_call` control blocking via `{ block: true, reason?: string, terminate?: boolean }`
766
+ - `terminate` only applies to a blocked call; the agent stops early only when every finalized result in the batch is terminating
766
767
 
767
768
  ```typescript
768
769
  import { isToolCallEventType } from "@earendil-works/pi-coding-agent";
@@ -778,7 +779,7 @@ pi.on("tool_call", async (event, ctx) => {
778
779
  event.input.command = `source ~/.profile\n${event.input.command}`;
779
780
 
780
781
  if (event.input.command.includes("rm -rf")) {
781
- return { block: true, reason: "Dangerous command" };
782
+ return { block: true, reason: "Dangerous command", terminate: true };
782
783
  }
783
784
  }
784
785
 
@@ -1425,12 +1426,16 @@ pi.sendUserMessage([
1425
1426
  // During streaming - must specify delivery mode
1426
1427
  pi.sendUserMessage("Focus on error handling", { deliverAs: "steer" });
1427
1428
  pi.sendUserMessage("And then summarize", { deliverAs: "followUp" });
1429
+
1430
+ // Opt in to extension command dispatch and skill/prompt template expansion
1431
+ pi.sendUserMessage("/review src/index.ts", { expandPromptTemplates: true });
1428
1432
  ```
1429
1433
 
1430
1434
  **Options:**
1431
1435
  - `deliverAs` - Required when agent is streaming:
1432
1436
  - `"steer"` - Queues the message for delivery after the current assistant turn finishes executing its tool calls
1433
1437
  - `"followUp"` - Waits for agent to finish all tools
1438
+ - `expandPromptTemplates` - Dispatch extension commands and expand skill commands and prompt templates. Defaults to `false`.
1434
1439
 
1435
1440
  When not streaming, the message is sent immediately and triggers a new turn. When streaming without `deliverAs`, throws an error.
1436
1441
 
package/bin/docs/json.md CHANGED
@@ -19,6 +19,7 @@ type JsonAgentSessionEvent =
19
19
  | Exclude<AgentSessionEvent, { type: "message_update" }>
20
20
  | {
21
21
  type: "message_update";
22
+ usage: Usage;
22
23
  assistantMessageEvent: WithoutPartial<AssistantMessageEvent>;
23
24
  };
24
25
  ```
@@ -73,16 +74,17 @@ Followed by events as they occur:
73
74
  {"type":"agent_start"}
74
75
  {"type":"turn_start"}
75
76
  {"type":"message_start","message":{"role":"assistant","content":[],...}}
76
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
77
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
77
78
  {"type":"message_end","message":{...}}
78
79
  {"type":"turn_end","message":{...},"toolResults":[]}
79
80
  {"type":"agent_end","messages":[...]}
80
81
  ```
81
82
 
82
83
  `message_update` records are delta-only. They omit both the cumulative `message` field and
83
- `assistantMessageEvent.partial` to keep stream size linear. Use `contentIndex` and `delta`
84
- to assemble live text, thinking, or tool-call arguments if needed. `message_end` contains
85
- the final authoritative message.
84
+ `assistantMessageEvent.partial` to keep stream size linear. The top-level `usage` field contains
85
+ the latest cumulative provider-reported usage and may remain zero when a provider only reports
86
+ usage at completion. Use `contentIndex` and `delta` to assemble live text, thinking, or tool-call
87
+ arguments if needed. `message_end` contains the final authoritative message.
86
88
 
87
89
  ## Example
88
90
 
@@ -10,7 +10,7 @@ After editing `keybindings.json`, run `/reload` in pi to apply the changes witho
10
10
 
11
11
  ## Key Format
12
12
 
13
- `modifier+key` where modifiers are `ctrl`, `shift`, `alt` (combinable) and keys are:
13
+ `modifier+key` where modifiers are `ctrl`, `shift`, `alt`, `super` (combinable) and keys are:
14
14
 
15
15
  - **Letters:** `a-z`
16
16
  - **Digits:** `0-9`
@@ -18,7 +18,9 @@ After editing `keybindings.json`, run `/reload` in pi to apply the changes witho
18
18
  - **Function:** `f1`-`f12`
19
19
  - **Symbols:** `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
20
20
 
21
- Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `ctrl+1`, etc.
21
+ Modifier combinations: `ctrl+shift+x`, `alt+ctrl+x`, `ctrl+shift+alt+x`, `super+k`, `ctrl+super+k`, `ctrl+1`, etc.
22
+
23
+ `super` bindings require a terminal that reports the modifier separately, typically through the Kitty keyboard protocol. They may not work in terminals without that support.
22
24
 
23
25
  ## All Actions
24
26
 
@@ -84,7 +86,7 @@ The dedicated history actions always change history entries, regardless of the c
84
86
 
85
87
  ### TUI Fullscreen Viewport
86
88
 
87
- These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content.
89
+ These actions apply when interactive mode uses `--tui-mode fullscreen` and target the primary transcript scroll region. Two-finger trackpad and mouse-wheel input scroll the region under the pointer, falling back to the transcript over the fixed editor/status/footer dock. Clicking an OSC 8 hyperlink opens it in the default handler. Dragging with the primary mouse button selects text and copies it to the clipboard; holding at the transcript's top or bottom edge auto-scrolls into off-screen content. See [Terminal setup](terminal-setup.md) for terminal-specific mouse and trackpad behavior.
88
90
 
89
91
  Fullscreen transcript bindings take precedence over editor bindings. The default unmodified navigation keys therefore control the transcript in fullscreen mode, while their `ctrl` variants continue to control the editor. Outside fullscreen mode, both variants control the editor.
90
92
 
@@ -95,14 +97,22 @@ Fullscreen transcript bindings take precedence over editor bindings. The default
95
97
  | `pageUp`, `pageDown` | Editor | Transcript |
96
98
  | `ctrl+pageUp`, `ctrl+pageDown` | Editor | Editor |
97
99
 
98
- This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
100
+ This routing remains configurable through the ordinary action bindings. For example, `"tui.altScreen.pageUp": "ctrl+pageUp"` makes `pageUp` control the editor and `ctrl+pageUp` control the transcript in fullscreen mode. Bind `tui.altScreen.halfPageUp` and `tui.altScreen.halfPageDown` for half-page steps, or bind `tui.altScreen.lineUp` and `tui.altScreen.lineDown` for single-line steps. Setting `"tui.altScreen.pageUp": []` disables that transcript shortcut entirely. User bindings replace the defaults for that action.
99
101
 
100
102
  | Keybinding id | Default | Description |
101
103
  |--------|---------|-------------|
102
104
  | `tui.altScreen.pageUp` | `pageUp` | Scroll the transcript up by one page |
103
105
  | `tui.altScreen.pageDown` | `pageDown` | Scroll the transcript down by one page |
106
+ | `tui.altScreen.halfPageUp` | *(none)* | Scroll the transcript up by half a page |
107
+ | `tui.altScreen.halfPageDown` | *(none)* | Scroll the transcript down by half a page |
108
+ | `tui.altScreen.lineUp` | *(none)* | Scroll the transcript up by one line |
109
+ | `tui.altScreen.lineDown` | *(none)* | Scroll the transcript down by one line |
104
110
  | `tui.altScreen.previousPrompt` | `ctrl+shift+up` | Jump to the previous marked message |
105
111
  | `tui.altScreen.nextPrompt` | `ctrl+shift+down` | Jump to the next marked message |
112
+ | `tui.altScreen.search` | `ctrl+shift+f` | Search the rendered transcript |
113
+ | `tui.altScreen.searchNext` | `enter`, `ctrl+g` | Select the next search match while searching |
114
+ | `tui.altScreen.searchPrevious` | `shift+enter`, `ctrl+shift+g` | Select the previous search match while searching |
115
+ | `tui.altScreen.searchClose` | `escape` | Close transcript search |
106
116
  | `tui.altScreen.top` | `home` | Scroll to the beginning of the transcript |
107
117
  | `tui.altScreen.bottom` | `end` | Scroll to the transcript end and follow new output |
108
118
 
@@ -111,11 +121,11 @@ This routing remains configurable through the ordinary action bindings. For exam
111
121
  | Keybinding id | Default | Description |
112
122
  |--------|---------|-------------|
113
123
  | `app.interrupt` | `escape` | Cancel / abort |
114
- | `app.clear` | `ctrl+c` | Clear editor |
124
+ | `app.clear` | `ctrl+c` | Clear editor (first) / exit (second) |
115
125
  | `app.exit` | `ctrl+d` | Exit (when editor empty) |
116
126
  | `app.suspend` | `ctrl+z` (none on Windows) | Suspend to background |
117
127
  | `app.editor.external` | `ctrl+g` | Open in external editor (`externalEditor`, `$VISUAL`, `$EDITOR`, Notepad on Windows, or `nano` elsewhere) |
118
- | `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image from clipboard |
128
+ | `app.clipboard.pasteImage` | `ctrl+v` (`alt+v` on Windows) | Paste image or text from clipboard |
119
129
 
120
130
  ### Sessions
121
131
 
@@ -96,7 +96,8 @@ pi
96
96
  | Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
97
97
  | MiniMax | `MINIMAX_API_KEY` | `minimax` |
98
98
  | MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
99
- | Qwen Token Plan | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan` |
99
+ | Qwen Token Plan (existing catalog) | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan` |
100
+ | Qwen Token Plan (Individual) | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan-individual` |
100
101
  | Qwen Token Plan (China) | `QWEN_TOKEN_PLAN_CN_API_KEY` | `qwen-token-plan-cn` |
101
102
  | Xiaomi MiMo | `XIAOMI_API_KEY` | `xiaomi` |
102
103
  | Xiaomi MiMo Token Plan (China) | `XIAOMI_TOKEN_PLAN_CN_API_KEY` | `xiaomi-token-plan-cn` |
@@ -121,6 +122,7 @@ Store credentials in `~/.pi/agent/auth.json`:
121
122
  "opencode-go": { "type": "api_key", "key": "..." },
122
123
  "together": { "type": "api_key", "key": "..." },
123
124
  "qwen-token-plan": { "type": "api_key", "key": "sk-sp-..." },
125
+ "qwen-token-plan-individual": { "type": "api_key", "key": "sk-sp-..." },
124
126
  "qwen-token-plan-cn": { "type": "api_key", "key": "sk-sp-..." },
125
127
  "xiaomi": { "type": "api_key", "key": "..." },
126
128
  "xiaomi-token-plan-cn": { "type": "api_key", "key": "..." },
@@ -129,6 +131,11 @@ Store credentials in `~/.pi/agent/auth.json`:
129
131
  }
130
132
  ```
131
133
 
134
+ `qwen-token-plan-individual` uses the same international endpoint and `QWEN_TOKEN_PLAN_API_KEY` as
135
+ `qwen-token-plan`, but limits the picker to the models documented for Individual subscriptions. The existing
136
+ provider keeps its broader catalog for backward compatibility. When using `auth.json`, store the
137
+ credential under the provider you select; an environment variable is shared by both international providers.
138
+
132
139
  The file is created with `0600` permissions (user read/write only). Auth file credentials take priority over environment variables.
133
140
 
134
141
  API key credentials can also include provider-scoped environment values. These values are used before process environment variables when resolving the credential key, provider/model headers, and provider configuration such as Cloudflare account IDs, Azure OpenAI settings, Vertex project/location, Bedrock settings, `PI_CACHE_RETENTION`, and `HTTP_PROXY`/`HTTPS_PROXY`.
package/bin/docs/rpc.md CHANGED
@@ -919,6 +919,14 @@ Emitted during streaming of assistant messages. Contains a delta event without a
919
919
  ```json
920
920
  {
921
921
  "type": "message_update",
922
+ "usage": {
923
+ "input": 100,
924
+ "output": 1,
925
+ "cacheRead": 0,
926
+ "cacheWrite": 0,
927
+ "totalTokens": 101,
928
+ "cost": {"input": 0, "output": 0, "cacheRead": 0, "cacheWrite": 0, "total": 0}
929
+ },
922
930
  "assistantMessageEvent": {
923
931
  "type": "text_delta",
924
932
  "contentIndex": 0,
@@ -943,12 +951,15 @@ The `assistantMessageEvent` field contains one of these delta types:
943
951
 
944
952
  Example streaming a text response:
945
953
  ```json
946
- {"type":"message_update","assistantMessageEvent":{"type":"text_start","contentIndex":0}}
947
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
948
- {"type":"message_update","assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world"}}
949
- {"type":"message_update","assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world"}}
954
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_start","contentIndex":0}}
955
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello"}}
956
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world"}}
957
+ {"type":"message_update","usage":{...},"assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world"}}
950
958
  ```
951
959
 
960
+ The top-level `usage` field contains the latest cumulative provider-reported usage. It may remain
961
+ zero until completion when a provider does not report usage during streaming.
962
+
952
963
  `message_update` intentionally omits the former cumulative `message` field and
953
964
  `assistantMessageEvent.partial`. Clients that need a live partial message must assemble it
954
965
  from `message_start` and subsequent events using `contentIndex`. Treat `message_end.message`
package/bin/docs/sdk.md CHANGED
@@ -372,6 +372,13 @@ import { ModelRuntime } from "@earendil-works/pi-coding-agent";
372
372
 
373
373
  const modelRuntime = await ModelRuntime.create();
374
374
 
375
+ // create() restores cached catalogs but does not refresh them from pi.dev by default.
376
+ // Opt in to a create-time network refresh and bound how long it may take:
377
+ const refreshedRuntime = await ModelRuntime.create({
378
+ allowModelNetwork: true,
379
+ modelRefreshTimeoutMs: 15_000,
380
+ });
381
+
375
382
  // Find specific built-in model (doesn't check if API key exists)
376
383
  const opus = getModel("anthropic", "claude-opus-4-5");
377
384
  if (!opus) throw new Error("Model not found");
@@ -402,6 +409,8 @@ If no model is provided:
402
409
  2. Uses default from settings
403
410
  3. Falls back to first available model
404
411
 
412
+ Remote catalogs are persisted locally so later runtimes can restore them without a network request. The default file is `~/.pi/agent/models-store.json`; set `modelsStorePath` to choose another location, or inject `modelsStore` to control persistence. Network refreshes are throttled to once per provider every four hours unless forced. To force an immediate refresh, call `await modelRuntime.refresh({ allowNetwork: true, force: true, signal })`. Setting `PI_OFFLINE` disables model network access.
413
+
405
414
  To match CLI model parsing, use the exported resolver helpers:
406
415
 
407
416
  ```typescript
@@ -66,6 +66,7 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
66
66
  | `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
67
67
  | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
68
68
  | `tuiMode` | string | `"regular"` | Interactive TUI mode: `"regular"` or experimental `"fullscreen"`. Changes from `/settings` apply immediately; `--tui-mode` overrides this setting at startup |
69
+ | `fullscreenExitOutput` | string | `"transcript"` | Fullscreen exit output: `"transcript"` prints the final transcript and resume hint, while `"resume-hint"` restores the previous screen and prints only the resume hint. Has no effect in regular TUI mode |
69
70
  | `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling, `"always"` reserves the rightmost column and keeps it visible, and `"hidden"` hides it. Has no effect in regular TUI mode |
70
71
 
71
72
  For VS Code, include `--wait` so pi resumes after the editor exits:
@@ -175,6 +176,7 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
175
176
  |---------|------|---------|-------------|
176
177
  | `steeringMode` | string | `"one-at-a-time"` | How steering messages are sent: `"all"` or `"one-at-a-time"` |
177
178
  | `followUpMode` | string | `"one-at-a-time"` | How follow-up messages are sent: `"all"` or `"one-at-a-time"` |
179
+ | `nonStreaming` | boolean | `false` | Request a single non-streaming response from capable providers. Currently supported by `openai-completions` APIs. |
178
180
  | `transport` | string | `"auto"` | Preferred transport for providers that support multiple transports: `"sse"`, `"websocket"`, `"websocket-cached"`, or `"auto"` |
179
181
  | `httpIdleTimeoutMs` | number | `300000` | HTTP header/body idle timeout in milliseconds, also used by providers with explicit stream idle timeouts. Set to `0` to disable. |
180
182
  | `websocketConnectTimeoutMs` | number | `15000` | WebSocket connect/open handshake timeout in milliseconds for providers that support WebSocket transports. Set to `0` to disable. |
@@ -197,6 +199,20 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
197
199
  | `shellCommandPrefix` | string | - | Prefix for every bash command (e.g., `"shopt -s expand_aliases"`) |
198
200
  | `npmCommand` | string[] | - | Command argv used for npm package lookup/install operations (e.g., `["mise", "exec", "node@20", "--", "npm"]`) |
199
201
 
202
+ Windows paths in JSON must use forward slashes or escaped backslashes:
203
+
204
+ ```json
205
+ {
206
+ "shellPath": "C:/Program Files/Git/bin/bash.exe"
207
+ }
208
+ ```
209
+
210
+ ```json
211
+ {
212
+ "shellPath": "C:\\Program Files\\Git\\bin\\bash.exe"
213
+ }
214
+ ```
215
+
200
216
  ```json
201
217
  {
202
218
  "npmCommand": ["mise", "exec", "node@20", "--", "npm"]
@@ -205,6 +221,22 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
205
221
 
206
222
  `npmCommand` is used for all npm package-manager operations, including installs, uninstalls, and dependency installs inside git packages. User-scoped npm packages install under `~/.pi/agent/npm/`; project-scoped npm packages install under `.pi/npm/`. Use argv-style entries exactly as the process should be launched. When `npmCommand` is configured, git package dependency installs use plain `install` to avoid npm-specific flags in wrappers or alternate package managers.
207
223
 
224
+ ### Tools
225
+
226
+ | Setting | Type | Default | Description |
227
+ |---------|------|---------|-------------|
228
+ | `defaultTools` | string[] | - | Built-in tools enabled initially. When omitted, Pi uses its standard defaults |
229
+
230
+ `defaultTools` selects the built-in tools enabled at startup. Extension and SDK custom tools remain enabled:
231
+
232
+ ```json
233
+ {
234
+ "defaultTools": ["bash", "edit", "write"]
235
+ }
236
+ ```
237
+
238
+ An empty array starts with no built-in tools while preserving extension and SDK custom tools. `--tools` replaces this behavior with a strict allowlist for all tools, `--no-tools` disables all tools, and `--no-builtin-tools` disables the built-in defaults. `--exclude-tools` filters the resulting list. A project `defaultTools` array replaces the global array.
239
+
208
240
  ### Sessions
209
241
 
210
242
  | Setting | Type | Default | Description |
@@ -2,9 +2,26 @@
2
2
 
3
3
  Pi uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier key detection. Most modern terminals support this protocol, but some require configuration.
4
4
 
5
- ## Kitty, iTerm2
5
+ ## Kitty
6
6
 
7
- Work out of the box.
7
+ Works out of the box.
8
+
9
+ ## iTerm2
10
+
11
+ ### Regular TUI mode
12
+
13
+ Works out of the box.
14
+
15
+ ### Fullscreen TUI mode
16
+
17
+ Pi owns the viewport, so iTerm2 sends mouse-wheel reports instead of scrolling its native scrollback. With iTerm2's default fast-trackpad behavior, those reports can lose most of an accelerated wheel delta, making fullscreen scrolling much slower than regular scrolling.
18
+
19
+ If fast mouse-wheel gestures move only about one line at a time in fullscreen mode:
20
+
21
+ 1. Open **iTerm2 → Settings → Advanced**.
22
+ 2. Search for **Trackpad scrolls fast?** and set it to **No**.
23
+
24
+ This is an iTerm2-wide workaround and may also change native trackpad scrolling. The underlying behavior is tracked in [iTerm2 issue 9619](https://gitlab.com/gnachman/iterm2/-/work_items/9619).
8
25
 
9
26
  ## Apple Terminal
10
27
 
@@ -32,6 +49,10 @@ If Claude Code 2.x or newer is the only reason you added that mapping, you can r
32
49
 
33
50
  Pi binds `Ctrl+J` as a default newline alias, so `Shift+Enter` keeps working in tmux via that remap without extra pi configuration.
34
51
 
52
+ ### Fullscreen TUI mode
53
+
54
+ In fullscreen mode, links remain clickable, but Ghostty does not show its hover underline or lower-left URL preview while pi captures mouse input. Hold `Shift+Command` on macOS or `Shift+Ctrl` on Linux to use Ghostty's native link handling.
55
+
35
56
  ## WezTerm
36
57
 
37
58
  WezTerm usually works out of the box for `Shift+Enter` via xterm modifyOtherKeys. To use the Kitty keyboard protocol explicitly, create `~/.wezterm.lua`:
@@ -39,6 +39,23 @@ Select a theme via `/settings` or in `settings.json`:
39
39
 
40
40
  On first run, pi detects your terminal background and defaults to `dark` or `light`.
41
41
 
42
+ ### Initial Theme
43
+
44
+ Start an interactive run with a theme without changing the saved setting:
45
+
46
+ ```bash
47
+ pi --use-theme light
48
+ ```
49
+
50
+ To follow terminal appearance, use `lightTheme/darkTheme` syntax:
51
+
52
+ ```bash
53
+ pi --use-theme light/dark
54
+ ```
55
+
56
+ The CLI value is the initial theme for that run. Choosing another theme later in `/settings` applies it immediately
57
+ and saves it normally.
58
+
42
59
  ## Creating a Custom Theme
43
60
 
44
61
  1. Create a theme file:
@@ -72,6 +89,8 @@ vim ~/.pi/agent/themes/my-theme.json
72
89
  "thinkingText": "secondary",
73
90
  "selectedBg": "#2d2d30",
74
91
  "scrollbarThumb": "#555566",
92
+ "searchMatchBg": "#2d2d30",
93
+ "searchMatchText": "",
75
94
  "userMessageBg": "#2d2d30",
76
95
  "userMessageText": "",
77
96
  "customMessageBg": "#2d2d30",
@@ -141,13 +160,13 @@ vim ~/.pi/agent/themes/my-theme.json
141
160
 
142
161
  - `name` is required, must be unique, and must not contain `/`.
143
162
  - `vars` is optional. Define reusable colors here, then reference them in `colors`.
144
- - `colors` must define all 51 required tokens. `thinkingMax` is optional and falls back to `thinkingXhigh`; `scrollbarThumb` is optional and falls back to `selectedBg`.
163
+ - `colors` must define all 51 required tokens. `thinkingMax`, `scrollbarThumb`, and the two search highlight tokens are optional and use the fallbacks listed below.
145
164
 
146
165
  The `$schema` field enables editor auto-completion and validation.
147
166
 
148
167
  ## Color Tokens
149
168
 
150
- Every theme must define all 51 required color tokens. `thinkingMax` and `scrollbarThumb` are optional for compatibility with existing themes; when omitted, they use `thinkingXhigh` and `selectedBg`, respectively.
169
+ Every theme must define all 51 required color tokens. The optional tokens preserve compatibility with existing themes: `thinkingMax` falls back to `thinkingXhigh`, `scrollbarThumb` and `searchMatchBg` fall back to `selectedBg`, and `searchMatchText` falls back to `text`. Other search matches use `searchMatchText` on `searchMatchBg` with an underline; the current match reverses that foreground/background pair and uses bold text.
151
170
 
152
171
  ### Core UI (11 colors)
153
172
 
@@ -165,12 +184,14 @@ Every theme must define all 51 required color tokens. `thinkingMax` and `scrollb
165
184
  | `text` | Default text (usually `""`) |
166
185
  | `thinkingText` | Thinking block text |
167
186
 
168
- ### Backgrounds & Content (11 required, 1 optional)
187
+ ### Backgrounds & Content (11 required, 3 optional)
169
188
 
170
189
  | Token | Purpose |
171
190
  |-------|---------|
172
191
  | `selectedBg` | Selected line background |
173
192
  | `scrollbarThumb` | Fullscreen scrollbar thumb background; optional, falls back to `selectedBg` |
193
+ | `searchMatchBg` | Transcript search match background and current-match text; optional, falls back to `selectedBg` |
194
+ | `searchMatchText` | Transcript search match text and current-match background; optional, falls back to `text` |
174
195
  | `userMessageBg` | User message background |
175
196
  | `userMessageText` | User message text |
176
197
  | `customMessageBg` | Extension message background |
package/bin/docs/tui.md CHANGED
@@ -431,7 +431,7 @@ renderResult(result, options, theme, context) {
431
431
 
432
432
  | Category | Colors |
433
433
  |----------|--------|
434
- | General | `text`, `accent`, `muted`, `dim` |
434
+ | General | `text`, `accent`, `muted`, `dim`, `searchMatchText` |
435
435
  | Status | `success`, `error`, `warning` |
436
436
  | Borders | `border`, `borderAccent`, `borderMuted` |
437
437
  | Messages | `userMessageText`, `customMessageText`, `customMessageLabel` |
@@ -444,7 +444,7 @@ renderResult(result, options, theme, context) {
444
444
 
445
445
  **Background colors** (`theme.bg(color, text)`):
446
446
 
447
- `selectedBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`
447
+ `selectedBg`, `searchMatchBg`, `userMessageBg`, `customMessageBg`, `toolPendingBg`, `toolSuccessBg`, `toolErrorBg`
448
448
 
449
449
  **For Markdown**, use `getMarkdownTheme()`:
450
450
 
package/bin/docs/usage.md CHANGED
@@ -242,15 +242,16 @@ pi --no-extensions -e ./my-extension.ts
242
242
  | `--system-prompt <text>` | Replace default prompt; context files and skills are still appended |
243
243
  | `--append-system-prompt <text>` | Append to system prompt |
244
244
  | `--tui-mode <mode>` | TUI mode: `regular` (default) or experimental `fullscreen` |
245
+ | `--use-theme <name[/name]>` | Set the initial interactive theme for this run without changing settings |
245
246
  | `--verbose` | Force verbose startup |
246
247
  | `-a`, `--approve` | Trust project-local files for this run |
247
248
  | `-na`, `--no-approve` | Ignore project-local files for this run |
248
249
  | `-h`, `--help` | Show help |
249
250
  | `-v`, `--version` | Show version |
250
251
 
251
- In `fullscreen` mode, the transcript scrolls inside the terminal viewport while queued messages, working status, extension widgets, editor, and footer remain fixed at the bottom. Mouse/trackpad input scrolls the region under the pointer; keyboard viewport actions always remain available. Inline images work in terminals that support the Kitty graphics protocol, including Kitty and Ghostty. In iTerm2 they render as text placeholders because its inline-image protocol cannot delete or crop placements during application-owned scrolling. In `regular` mode, pi uses the main screen and terminal-owned scrollback, and iTerm2 inline images continue to render normally.
252
+ In `fullscreen` mode, the transcript scrolls inside the terminal viewport while queued messages, working status, extension widgets, editor, and footer remain fixed at the bottom. Mouse/trackpad input scrolls the region under the pointer; keyboard viewport actions always remain available. Inline images work in terminals that support the Kitty graphics protocol, including Kitty and Ghostty. In iTerm2 they render as text placeholders because its inline-image protocol cannot delete or crop placements during application-owned scrolling. In `regular` mode, pi uses the main screen and terminal-owned scrollback, and iTerm2 inline images continue to render normally. See [Terminal setup](terminal-setup.md) for terminal-specific settings and workarounds.
252
253
 
253
- Set **TUI mode** in `/settings` to switch between `regular` and `fullscreen` immediately and choose the default for future sessions.
254
+ Set **TUI mode** in `/settings` to switch between `regular` and `fullscreen` immediately and choose the default for future sessions. **Fullscreen exit output** controls whether exiting fullscreen prints the final transcript or restores the previous screen and prints only the session resume hint.
254
255
 
255
256
  ### File Arguments
256
257
 
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.84.0",
3
+ "version": "0.84.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.84.0",
9
+ "version": "0.84.2",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.84.0",
4
+ "version": "0.84.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.84.0",
4
+ "version": "0.84.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
- "version": "0.84.0",
3
+ "version": "0.84.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-gondolin",
9
- "version": "0.84.0",
9
+ "version": "0.84.2",
10
10
  "dependencies": {
11
11
  "@earendil-works/gondolin": "0.12.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
3
  "private": true,
4
- "version": "0.84.0",
4
+ "version": "0.84.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "1.14.0",
3
+ "version": "1.14.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "1.14.0",
9
+ "version": "1.14.2",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "1.14.0",
4
+ "version": "1.14.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -137,6 +137,8 @@ model: claude-haiku-4-5
137
137
  System prompt for the agent goes here.
138
138
  ```
139
139
 
140
+ When `model` is omitted, the subagent inherits the dispatching session's active model and thinking level.
141
+
140
142
  **Locations:**
141
143
  - `~/.pi/agent/agents/*.md` - User-level (always loaded)
142
144
  - `.pi/agents/*.md` - Project-level (only with `agentScope: "project"` or `"both"`)
@@ -23,6 +23,42 @@ export interface AgentDiscoveryResult {
23
23
  projectAgentsDir: string | null;
24
24
  }
25
25
 
26
+ /**
27
+ * Raw agent frontmatter. Values are `unknown` because `parseFrontmatter` runs a
28
+ * real YAML parser, so any scalar or collection can appear here.
29
+ *
30
+ * A type alias rather than an interface: `parseFrontmatter` constrains its
31
+ * parameter to `Record<string, unknown>`, and only an alias picks up the
32
+ * implicit index signature that satisfies it.
33
+ */
34
+ type AgentFrontmatter = {
35
+ name?: unknown;
36
+ description?: unknown;
37
+ tools?: unknown;
38
+ model?: unknown;
39
+ };
40
+
41
+ /**
42
+ * Normalize a frontmatter `tools` value to a list of tool names.
43
+ *
44
+ * Both spellings are valid YAML and both are in use:
45
+ *
46
+ * tools: read, bash # string
47
+ * tools: [read, bash] # array
48
+ *
49
+ * so accept either. Anything else (a number, a map, a nested list) yields no
50
+ * tools rather than throwing: this runs inside agent discovery, where a single
51
+ * bad file must not take down every other agent in the same directory.
52
+ */
53
+ function parseToolList(value: unknown): string[] | undefined {
54
+ const raw = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
55
+ const tools = raw
56
+ .filter((t): t is string => typeof t === "string")
57
+ .map((t) => t.trim())
58
+ .filter(Boolean);
59
+ return tools.length > 0 ? tools : undefined;
60
+ }
61
+
26
62
  function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig[] {
27
63
  const agents: AgentConfig[] = [];
28
64
 
@@ -49,22 +85,17 @@ function loadAgentsFromDir(dir: string, source: "user" | "project"): AgentConfig
49
85
  continue;
50
86
  }
51
87
 
52
- const { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);
88
+ const { frontmatter, body } = parseFrontmatter<AgentFrontmatter>(content);
53
89
 
54
- if (!frontmatter.name || !frontmatter.description) {
90
+ if (typeof frontmatter.name !== "string" || typeof frontmatter.description !== "string") {
55
91
  continue;
56
92
  }
57
93
 
58
- const tools = frontmatter.tools
59
- ?.split(",")
60
- .map((t: string) => t.trim())
61
- .filter(Boolean);
62
-
63
94
  agents.push({
64
95
  name: frontmatter.name,
65
96
  description: frontmatter.description,
66
- tools: tools && tools.length > 0 ? tools : undefined,
67
- model: frontmatter.model,
97
+ tools: parseToolList(frontmatter.tools),
98
+ model: typeof frontmatter.model === "string" ? frontmatter.model : undefined,
68
99
  systemPrompt: body,
69
100
  source,
70
101
  filePath,
@@ -16,7 +16,7 @@ import { spawn } from "node:child_process";
16
16
  import * as fs from "node:fs";
17
17
  import * as os from "node:os";
18
18
  import * as path from "node:path";
19
- import type { AgentToolResult } from "@earendil-works/pi-agent-core";
19
+ import type { AgentToolResult, ThinkingLevel } from "@earendil-works/pi-agent-core";
20
20
  import type { Message } from "@earendil-works/pi-ai";
21
21
  import { StringEnum } from "@earendil-works/pi-ai";
22
22
  import {
@@ -264,8 +264,14 @@ function getPiInvocation(args: string[]): { command: string; args: string[] } {
264
264
 
265
265
  type OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;
266
266
 
267
+ interface DispatchDefaults {
268
+ model?: string;
269
+ thinkingLevel?: ThinkingLevel;
270
+ }
271
+
267
272
  async function runSingleAgent(
268
273
  defaultCwd: string,
274
+ dispatchDefaults: DispatchDefaults,
269
275
  agents: AgentConfig[],
270
276
  agentName: string,
271
277
  task: string,
@@ -292,7 +298,12 @@ async function runSingleAgent(
292
298
  }
293
299
 
294
300
  const args: string[] = ["--mode", "json", "-p", "--no-session"];
295
- if (agent.model) args.push("--model", agent.model);
301
+ const inheritsDispatchConfig = !agent.model;
302
+ const model = agent.model ?? dispatchDefaults.model;
303
+ if (model) args.push("--model", model);
304
+ if (inheritsDispatchConfig && dispatchDefaults.thinkingLevel) {
305
+ args.push("--thinking", dispatchDefaults.thinkingLevel);
306
+ }
296
307
  if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
297
308
 
298
309
  let tmpPromptDir: string | null = null;
@@ -306,7 +317,7 @@ async function runSingleAgent(
306
317
  messages: [],
307
318
  stderr: "",
308
319
  usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
309
- model: agent.model,
320
+ model,
310
321
  step,
311
322
  };
312
323
 
@@ -471,6 +482,10 @@ export default function (pi: ExtensionAPI) {
471
482
 
472
483
  async execute(_toolCallId, params, signal, onUpdate, ctx) {
473
484
  const agentScope: AgentScope = params.agentScope ?? "user";
485
+ const dispatchDefaults: DispatchDefaults = {
486
+ model: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined,
487
+ thinkingLevel: ctx.thinkingLevel,
488
+ };
474
489
  const discovery = discoverAgents(ctx.cwd, agentScope);
475
490
  const agents = discovery.agents;
476
491
  const confirmProjectAgents = params.confirmProjectAgents ?? true;
@@ -552,6 +567,7 @@ export default function (pi: ExtensionAPI) {
552
567
 
553
568
  const result = await runSingleAgent(
554
569
  ctx.cwd,
570
+ dispatchDefaults,
555
571
  agents,
556
572
  step.agent,
557
573
  taskWithContext,
@@ -624,6 +640,7 @@ export default function (pi: ExtensionAPI) {
624
640
  const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
625
641
  const result = await runSingleAgent(
626
642
  ctx.cwd,
643
+ dispatchDefaults,
627
644
  agents,
628
645
  t.agent,
629
646
  t.task,
@@ -666,6 +683,7 @@ export default function (pi: ExtensionAPI) {
666
683
  if (params.agent && params.task) {
667
684
  const result = await runSingleAgent(
668
685
  ctx.cwd,
686
+ dispatchDefaults,
669
687
  agents,
670
688
  params.agent,
671
689
  params.task,
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.84.0",
3
+ "version": "0.84.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.84.0",
9
+ "version": "0.84.2",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.84.0",
4
+ "version": "0.84.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
package/bin/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-coding-agent",
3
- "version": "0.84.0",
3
+ "version": "0.84.2",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -35,7 +35,7 @@
35
35
  "scripts": {
36
36
  "clean": "shx rm -rf dist",
37
37
  "build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js dist/rpc-entry.js && npm run copy-assets",
38
- "build:binary": "npm --prefix ../tui run build && npm --prefix ../telemetry run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm --prefix ../protocol run build && npm --prefix ../client run build && npm run build && bun build --compile ./dist/bun/cli.js ./src/utils/image-resize-worker.ts --outfile dist/pi && npm run copy-binary-assets",
38
+ "build:binary": "npm --prefix ../tui run build && npm --prefix ../telemetry run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm --prefix ../protocol run build && npm --prefix ../client run build && npm run build && bun build --compile --no-compile-autoload-bunfig ./dist/bun/cli.js ./src/utils/image-resize-worker.ts --outfile dist/pi && npm run copy-binary-assets",
39
39
  "copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
40
40
  "copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
41
41
  "test": "vitest --run",
@@ -43,11 +43,11 @@
43
43
  "prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
44
44
  },
45
45
  "dependencies": {
46
- "@earendil-works/pi-agent-core": "^0.84.0",
47
- "@earendil-works/pi-ai": "^0.84.0",
48
- "@earendil-works/pi-client": "^0.84.0",
49
- "@earendil-works/pi-protocol": "^0.84.0",
50
- "@earendil-works/pi-tui": "^0.84.0",
46
+ "@earendil-works/pi-agent-core": "^0.84.2",
47
+ "@earendil-works/pi-ai": "^0.84.2",
48
+ "@earendil-works/pi-client": "^0.84.2",
49
+ "@earendil-works/pi-protocol": "^0.84.2",
50
+ "@earendil-works/pi-tui": "^0.84.2",
51
51
  "@silvia-odwyer/photon-node": "0.3.4",
52
52
  "chalk": "5.6.2",
53
53
  "cross-spawn": "7.0.6",
package/bin/pi.exe CHANGED
Binary file
@@ -34,6 +34,8 @@
34
34
 
35
35
  "selectedBg": "selectedBg",
36
36
  "scrollbarThumb": "selectedBg",
37
+ "searchMatchBg": "selectedBg",
38
+ "searchMatchText": "text",
37
39
  "userMessageBg": "userMsgBg",
38
40
  "userMessageText": "text",
39
41
  "customMessageBg": "customMsgBg",
@@ -33,6 +33,8 @@
33
33
 
34
34
  "selectedBg": "selectedBg",
35
35
  "scrollbarThumb": "selectedBg",
36
+ "searchMatchBg": "selectedBg",
37
+ "searchMatchText": "text",
36
38
  "userMessageBg": "userMsgBg",
37
39
  "userMessageText": "text",
38
40
  "customMessageBg": "customMsgBg",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "colors": {
36
36
  "type": "object",
37
- "description": "Theme color definitions (thinkingMax and scrollbarThumb are optional and use compatible fallbacks)",
37
+ "description": "Theme color definitions (thinkingMax, scrollbarThumb, and search highlight colors are optional and use compatible fallbacks)",
38
38
  "required": [
39
39
  "accent",
40
40
  "border",
@@ -141,6 +141,14 @@
141
141
  "$ref": "#/$defs/colorValue",
142
142
  "description": "Fullscreen scrollbar thumb background (falls back to selectedBg when omitted)"
143
143
  },
144
+ "searchMatchBg": {
145
+ "$ref": "#/$defs/colorValue",
146
+ "description": "Transcript search match background and current-match text (falls back to selectedBg when omitted)"
147
+ },
148
+ "searchMatchText": {
149
+ "$ref": "#/$defs/colorValue",
150
+ "description": "Transcript search match text and current-match background (falls back to text when omitted)"
151
+ },
144
152
  "userMessageBg": {
145
153
  "$ref": "#/$defs/colorValue",
146
154
  "description": "User message background"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kingingwang/pi-windows-x64",
3
- "version": "0.84.0",
3
+ "version": "0.84.2",
4
4
  "description": "Pi standalone binary for windows-x64 (fork distribution)",
5
5
  "license": "MIT",
6
6
  "os": [