@astralyn/pi 0.82.6 → 0.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (263) hide show
  1. package/CHANGELOG.md +61 -5099
  2. package/README.md +12 -111
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +9 -2
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/cli/credential-print.d.ts +23 -0
  7. package/dist/cli/credential-print.d.ts.map +1 -0
  8. package/dist/cli/credential-print.js +116 -0
  9. package/dist/cli/credential-print.js.map +1 -0
  10. package/dist/cli/session-picker.d.ts.map +1 -1
  11. package/dist/cli/session-picker.js +11 -13
  12. package/dist/cli/session-picker.js.map +1 -1
  13. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  14. package/dist/core/agent-session-runtime.js +3 -0
  15. package/dist/core/agent-session-runtime.js.map +1 -1
  16. package/dist/core/agent-session.d.ts +1 -1
  17. package/dist/core/agent-session.d.ts.map +1 -1
  18. package/dist/core/agent-session.js +13 -6
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/extensions/runner.d.ts +1 -0
  21. package/dist/core/extensions/runner.d.ts.map +1 -1
  22. package/dist/core/extensions/runner.js +7 -0
  23. package/dist/core/extensions/runner.js.map +1 -1
  24. package/dist/core/extensions/types.d.ts +11 -0
  25. package/dist/core/extensions/types.d.ts.map +1 -1
  26. package/dist/core/extensions/types.js.map +1 -1
  27. package/dist/core/footer-data-provider.d.ts +10 -0
  28. package/dist/core/footer-data-provider.d.ts.map +1 -1
  29. package/dist/core/footer-data-provider.js +1 -1
  30. package/dist/core/footer-data-provider.js.map +1 -1
  31. package/dist/core/model-runtime.d.ts +2 -0
  32. package/dist/core/model-runtime.d.ts.map +1 -1
  33. package/dist/core/model-runtime.js.map +1 -1
  34. package/dist/core/package-manager.d.ts.map +1 -1
  35. package/dist/core/package-manager.js +13 -6
  36. package/dist/core/package-manager.js.map +1 -1
  37. package/dist/core/resource-loader.d.ts +15 -0
  38. package/dist/core/resource-loader.d.ts.map +1 -1
  39. package/dist/core/resource-loader.js +70 -9
  40. package/dist/core/resource-loader.js.map +1 -1
  41. package/dist/core/session-manager.d.ts.map +1 -1
  42. package/dist/core/session-manager.js +2 -2
  43. package/dist/core/session-manager.js.map +1 -1
  44. package/dist/core/tools/bash.d.ts +1 -5
  45. package/dist/core/tools/bash.d.ts.map +1 -1
  46. package/dist/core/tools/bash.js +16 -41
  47. package/dist/core/tools/bash.js.map +1 -1
  48. package/dist/core/tools/edit.d.ts.map +1 -1
  49. package/dist/core/tools/edit.js +42 -11
  50. package/dist/core/tools/edit.js.map +1 -1
  51. package/dist/core/tools/find.d.ts.map +1 -1
  52. package/dist/core/tools/find.js +40 -11
  53. package/dist/core/tools/find.js.map +1 -1
  54. package/dist/core/tools/grep.d.ts.map +1 -1
  55. package/dist/core/tools/grep.js +17 -8
  56. package/dist/core/tools/grep.js.map +1 -1
  57. package/dist/core/tools/ls.d.ts.map +1 -1
  58. package/dist/core/tools/ls.js +3 -3
  59. package/dist/core/tools/ls.js.map +1 -1
  60. package/dist/core/tools/read.d.ts.map +1 -1
  61. package/dist/core/tools/read.js +4 -4
  62. package/dist/core/tools/read.js.map +1 -1
  63. package/dist/core/tools/render-utils.d.ts +7 -0
  64. package/dist/core/tools/render-utils.d.ts.map +1 -1
  65. package/dist/core/tools/render-utils.js +11 -0
  66. package/dist/core/tools/render-utils.js.map +1 -1
  67. package/dist/core/tools/write.d.ts.map +1 -1
  68. package/dist/core/tools/write.js +2 -3
  69. package/dist/core/tools/write.js.map +1 -1
  70. package/dist/core/trust-manager.d.ts.map +1 -1
  71. package/dist/core/trust-manager.js +48 -9
  72. package/dist/core/trust-manager.js.map +1 -1
  73. package/dist/extensions/deepwiki/render.d.ts.map +1 -1
  74. package/dist/extensions/deepwiki/render.js +34 -22
  75. package/dist/extensions/deepwiki/render.js.map +1 -1
  76. package/dist/extensions/index.d.ts.map +1 -1
  77. package/dist/extensions/index.js +0 -2
  78. package/dist/extensions/index.js.map +1 -1
  79. package/dist/extensions/llama/provider.d.ts.map +1 -1
  80. package/dist/extensions/llama/provider.js +1 -1
  81. package/dist/extensions/llama/provider.js.map +1 -1
  82. package/dist/extensions/question/dialog.d.ts.map +1 -1
  83. package/dist/extensions/question/dialog.js +29 -10
  84. package/dist/extensions/question/dialog.js.map +1 -1
  85. package/dist/extensions/question/index.d.ts.map +1 -1
  86. package/dist/extensions/question/index.js +7 -2
  87. package/dist/extensions/question/index.js.map +1 -1
  88. package/dist/extensions/question/render.d.ts +4 -8
  89. package/dist/extensions/question/render.d.ts.map +1 -1
  90. package/dist/extensions/question/render.js +202 -29
  91. package/dist/extensions/question/render.js.map +1 -1
  92. package/dist/extensions/question/results.d.ts.map +1 -1
  93. package/dist/extensions/question/results.js +1 -0
  94. package/dist/extensions/question/results.js.map +1 -1
  95. package/dist/extensions/question/schema.d.ts.map +1 -1
  96. package/dist/extensions/question/schema.js +2 -2
  97. package/dist/extensions/question/schema.js.map +1 -1
  98. package/dist/extensions/question/types.d.ts +1 -0
  99. package/dist/extensions/question/types.d.ts.map +1 -1
  100. package/dist/extensions/question/types.js +1 -1
  101. package/dist/extensions/question/types.js.map +1 -1
  102. package/dist/extensions/router/stream.d.ts +1 -0
  103. package/dist/extensions/router/stream.d.ts.map +1 -1
  104. package/dist/extensions/router/stream.js +44 -13
  105. package/dist/extensions/router/stream.js.map +1 -1
  106. package/dist/extensions/subagent/constants.d.ts +1 -0
  107. package/dist/extensions/subagent/constants.d.ts.map +1 -1
  108. package/dist/extensions/subagent/constants.js +1 -0
  109. package/dist/extensions/subagent/constants.js.map +1 -1
  110. package/dist/extensions/subagent/index.d.ts.map +1 -1
  111. package/dist/extensions/subagent/index.js +2 -0
  112. package/dist/extensions/subagent/index.js.map +1 -1
  113. package/dist/extensions/subagent/render.d.ts.map +1 -1
  114. package/dist/extensions/subagent/render.js +121 -48
  115. package/dist/extensions/subagent/render.js.map +1 -1
  116. package/dist/extensions/subagent/retry.d.ts +17 -0
  117. package/dist/extensions/subagent/retry.d.ts.map +1 -0
  118. package/dist/extensions/subagent/retry.js +41 -0
  119. package/dist/extensions/subagent/retry.js.map +1 -0
  120. package/dist/extensions/subagent/runner.d.ts.map +1 -1
  121. package/dist/extensions/subagent/runner.js +33 -5
  122. package/dist/extensions/subagent/runner.js.map +1 -1
  123. package/dist/extensions/subagent/sdk-runner.d.ts +6 -0
  124. package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
  125. package/dist/extensions/subagent/sdk-runner.js +46 -24
  126. package/dist/extensions/subagent/sdk-runner.js.map +1 -1
  127. package/dist/extensions/subagent/types.d.ts +7 -0
  128. package/dist/extensions/subagent/types.d.ts.map +1 -1
  129. package/dist/extensions/subagent/types.js.map +1 -1
  130. package/dist/extensions/todo/index.d.ts.map +1 -1
  131. package/dist/extensions/todo/index.js +1 -1
  132. package/dist/extensions/todo/index.js.map +1 -1
  133. package/dist/extensions/todo/state.d.ts.map +1 -1
  134. package/dist/extensions/todo/state.js +10 -2
  135. package/dist/extensions/todo/state.js.map +1 -1
  136. package/dist/extensions/todo/view.d.ts +1 -1
  137. package/dist/extensions/todo/view.d.ts.map +1 -1
  138. package/dist/extensions/todo/view.js +179 -34
  139. package/dist/extensions/todo/view.js.map +1 -1
  140. package/dist/main.d.ts.map +1 -1
  141. package/dist/main.js +43 -0
  142. package/dist/main.js.map +1 -1
  143. package/dist/migrations.d.ts.map +1 -1
  144. package/dist/migrations.js +2 -1
  145. package/dist/migrations.js.map +1 -1
  146. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  147. package/dist/modes/interactive/components/armin.js +5 -0
  148. package/dist/modes/interactive/components/armin.js.map +1 -1
  149. package/dist/modes/interactive/components/bash-execution.d.ts +1 -0
  150. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/bash-execution.js +4 -2
  152. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  153. package/dist/modes/interactive/components/countdown-timer.d.ts +13 -6
  154. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/countdown-timer.js +54 -17
  156. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  157. package/dist/modes/interactive/components/extension-selector.d.ts +1 -1
  158. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  159. package/dist/modes/interactive/components/extension-selector.js +10 -6
  160. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  161. package/dist/modes/interactive/components/keybinding-hints.d.ts +11 -1
  162. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  163. package/dist/modes/interactive/components/keybinding-hints.js +56 -0
  164. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  165. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  166. package/dist/modes/interactive/components/model-selector.js +4 -1
  167. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  168. package/dist/modes/interactive/components/session-selector.d.ts +3 -0
  169. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  170. package/dist/modes/interactive/components/session-selector.js +52 -2
  171. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  172. package/dist/modes/interactive/components/tool-execution.d.ts +10 -0
  173. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  174. package/dist/modes/interactive/components/tool-execution.js +133 -18
  175. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  176. package/dist/modes/interactive/components/tool-group.d.ts +1 -0
  177. package/dist/modes/interactive/components/tool-group.d.ts.map +1 -1
  178. package/dist/modes/interactive/components/tool-group.js +5 -0
  179. package/dist/modes/interactive/components/tool-group.js.map +1 -1
  180. package/dist/modes/interactive/components/tree-selector.d.ts +10 -1
  181. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  182. package/dist/modes/interactive/components/tree-selector.js +55 -2
  183. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  184. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  185. package/dist/modes/interactive/external-editor.js +40 -3
  186. package/dist/modes/interactive/external-editor.js.map +1 -1
  187. package/dist/modes/interactive/interactive-mode.d.ts +5 -0
  188. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  189. package/dist/modes/interactive/interactive-mode.js +92 -24
  190. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  191. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  192. package/dist/modes/interactive/theme/theme.js +3 -2
  193. package/dist/modes/interactive/theme/theme.js.map +1 -1
  194. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  195. package/dist/modes/rpc/rpc-mode.js +13 -0
  196. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  197. package/dist/utils/paths.d.ts +5 -0
  198. package/dist/utils/paths.d.ts.map +1 -1
  199. package/dist/utils/paths.js +7 -0
  200. package/dist/utils/paths.js.map +1 -1
  201. package/docs/bundled/README.md +13 -15
  202. package/docs/bundled/extensions/deepwiki.md +1 -1
  203. package/docs/bundled/extensions/question.md +7 -5
  204. package/docs/bundled/extensions/router.md +3 -4
  205. package/docs/bundled/extensions/statusline.md +0 -1
  206. package/docs/bundled/extensions/subagent.md +4 -3
  207. package/docs/bundled/extensions/todo.md +1 -1
  208. package/docs/bundled/themes.md +1 -1
  209. package/docs/bundled/tool-presentation.md +17 -16
  210. package/docs/compaction.md +25 -30
  211. package/docs/custom-provider.md +298 -583
  212. package/docs/docs.json +0 -8
  213. package/docs/extensions.md +132 -121
  214. package/docs/index.md +18 -74
  215. package/docs/json.md +20 -14
  216. package/docs/models.md +193 -151
  217. package/docs/providers.md +2 -1
  218. package/docs/quickstart.md +3 -3
  219. package/docs/rpc.md +166 -124
  220. package/docs/sdk.md +119 -178
  221. package/docs/security.md +1 -1
  222. package/docs/session-format.md +139 -119
  223. package/docs/skills.md +0 -1
  224. package/docs/themes.md +2 -2
  225. package/docs/tui.md +411 -549
  226. package/docs/usage.md +3 -11
  227. package/examples/README.md +6 -1
  228. package/examples/extensions/README.md +13 -33
  229. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  230. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  231. package/examples/extensions/truncated-tool.ts +2 -2
  232. package/examples/sdk/12-full-control.ts +2 -0
  233. package/npm-shrinkwrap.json +25 -25
  234. package/package.json +5 -5
  235. package/dist/extensions/plan/constants.d.ts +0 -40
  236. package/dist/extensions/plan/constants.d.ts.map +0 -1
  237. package/dist/extensions/plan/constants.js +0 -69
  238. package/dist/extensions/plan/constants.js.map +0 -1
  239. package/dist/extensions/plan/index.d.ts +0 -3
  240. package/dist/extensions/plan/index.d.ts.map +0 -1
  241. package/dist/extensions/plan/index.js +0 -323
  242. package/dist/extensions/plan/index.js.map +0 -1
  243. package/dist/extensions/plan/schema.d.ts +0 -15
  244. package/dist/extensions/plan/schema.d.ts.map +0 -1
  245. package/dist/extensions/plan/schema.js +0 -13
  246. package/dist/extensions/plan/schema.js.map +0 -1
  247. package/dist/extensions/plan/state.d.ts +0 -29
  248. package/dist/extensions/plan/state.d.ts.map +0 -1
  249. package/dist/extensions/plan/state.js +0 -74
  250. package/dist/extensions/plan/state.js.map +0 -1
  251. package/dist/extensions/plan/storage.d.ts +0 -18
  252. package/dist/extensions/plan/storage.d.ts.map +0 -1
  253. package/dist/extensions/plan/storage.js +0 -58
  254. package/dist/extensions/plan/storage.js.map +0 -1
  255. package/dist/extensions/plan/view.d.ts +0 -36
  256. package/dist/extensions/plan/view.d.ts.map +0 -1
  257. package/dist/extensions/plan/view.js +0 -74
  258. package/dist/extensions/plan/view.js.map +0 -1
  259. package/docs/bundled/extensions/README.md +0 -19
  260. package/docs/bundled/extensions/plan.md +0 -33
  261. package/examples/extensions/plan-mode/README.md +0 -66
  262. package/examples/extensions/plan-mode/index.ts +0 -390
  263. package/examples/extensions/plan-mode/utils.ts +0 -168
package/docs/docs.json CHANGED
@@ -56,18 +56,10 @@
56
56
  "title": "Overview",
57
57
  "path": "bundled/README.md"
58
58
  },
59
- {
60
- "title": "Extension catalog",
61
- "path": "bundled/extensions/README.md"
62
- },
63
59
  {
64
60
  "title": "DeepWiki",
65
61
  "path": "bundled/extensions/deepwiki.md"
66
62
  },
67
- {
68
- "title": "Plan",
69
- "path": "bundled/extensions/plan.md"
70
- },
71
63
  {
72
64
  "title": "Question",
73
65
  "path": "bundled/extensions/question.md"
@@ -26,7 +26,7 @@ Extensions are TypeScript modules that extend pi's behavior. They can subscribe
26
26
  - External integrations (file watchers, webhooks, CI triggers)
27
27
  - Games while you wait (see `snake.ts` example)
28
28
 
29
- See [examples/extensions/](../examples/extensions/) for working implementations.
29
+ See the [extension examples catalog](../examples/extensions/README.md) for working implementations.
30
30
 
31
31
  ## Table of Contents
32
32
 
@@ -49,9 +49,10 @@ See [examples/extensions/](../examples/extensions/) for working implementations.
49
49
  - [Custom Tools](#custom-tools)
50
50
  - [Dynamic Tool Loading](#dynamic-tool-loading)
51
51
  - [Custom UI](#custom-ui)
52
+ - [Terminal Input](#terminal-input)
52
53
  - [Error Handling](#error-handling)
53
54
  - [Mode Behavior](#mode-behavior)
54
- - [Examples Reference](#examples-reference)
55
+ - [Examples](#examples)
55
56
 
56
57
  ## Quick Start
57
58
 
@@ -143,6 +144,7 @@ To share extensions via npm or git as pi packages, see [packages.md](packages.md
143
144
  | `@astralyn/pi` | Extension types (`ExtensionAPI`, `ExtensionContext`, events) |
144
145
  | `typebox` | Schema definitions for tool parameters |
145
146
  | `@earendil-works/pi-ai` | AI utilities (`StringEnum` for Google-compatible enums) |
147
+ | `@earendil-works/pi-agent-core` | Agent-core types for advanced integrations |
146
148
  | `@earendil-works/pi-tui` | TUI components for custom rendering |
147
149
 
148
150
  npm dependencies work too. Add a `package.json` next to your extension (or in a parent directory), run `npm install`, and imports from `node_modules/` are resolved automatically.
@@ -490,8 +492,16 @@ Fired on `/tree` navigation. See [Sessions](sessions.md) for tree navigation con
490
492
  ```typescript
491
493
  pi.on("session_before_tree", async (event, ctx) => {
492
494
  const { preparation, signal } = event;
495
+ // preparation: targetId, oldLeafId, commonAncestorId, entriesToSummarize,
496
+ // userWantsSummary, customInstructions, replaceInstructions, label
493
497
  return { cancel: true };
494
- // OR provide custom summary:
498
+ // OR customize the built-in summarizer:
499
+ return {
500
+ customInstructions: "Preserve decisions and open questions.",
501
+ replaceInstructions: false,
502
+ label: "review-checkpoint",
503
+ };
504
+ // OR provide a custom summary (used only when navigation requests a summary):
495
505
  return {
496
506
  summary: {
497
507
  summary: "...",
@@ -502,10 +512,12 @@ pi.on("session_before_tree", async (event, ctx) => {
502
512
  });
503
513
 
504
514
  pi.on("session_tree", async (event, ctx) => {
505
- // event.newLeafId, oldLeafId, summaryEntry, fromExtension
515
+ // event.newLeafId, event.oldLeafId, event.summaryEntry, event.fromExtension
506
516
  });
507
517
  ```
508
518
 
519
+ `customInstructions` and `replaceInstructions` override the corresponding options for Pi's built-in branch summarizer. `label` overrides the label attached to the generated summary, or to the target when not summarizing. `summary` replaces the built-in summarizer only when the navigation requested a summary; otherwise it is ignored. `cancel` stops navigation.
520
+
509
521
  #### session_shutdown
510
522
 
511
523
  Fired before a started session runtime is torn down. Use this to clean up resources opened from `session_start` or other session-scoped hooks.
@@ -513,7 +525,7 @@ Fired before a started session runtime is torn down. Use this to clean up resour
513
525
  ```typescript
514
526
  pi.on("session_shutdown", async (event, ctx) => {
515
527
  // event.reason - "quit" | "reload" | "new" | "resume" | "fork"
516
- // event.targetSessionFile - destination session for session replacement flows
528
+ // event.targetSessionFile - destination for new/resume/fork replacement, if persisted
517
529
  // Cleanup, save state, etc.
518
530
  });
519
531
  ```
@@ -986,9 +998,11 @@ ctx.sessionManager.buildContextEntries() // Active branch entries with compac
986
998
  ctx.sessionManager.getLeafId() // Current leaf entry ID
987
999
  ```
988
1000
 
989
- ### ctx.modelRegistry / ctx.model / ctx.thinkingLevel
1001
+ ### ctx.modelRegistry / ctx.model / ctx.thinkingLevel / ctx.scopedModels
990
1002
 
991
- Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model, and `ctx.thinkingLevel` is its current effective thinking level.
1003
+ Access to models, providers, and resolved authentication. `ctx.modelRegistry.getProvider(id)` returns the effective pi-ai provider, while `getProviderAuth(id)` resolves its current API key, headers, base URL, and provider-scoped environment without requiring a loaded model. `ctx.model` is the active model (or `undefined` when none is active), and `ctx.thinkingLevel` is its current effective thinking level when the session runtime provides one.
1004
+
1005
+ `ctx.scopedModels` is the read-only list of models scoped to the current session—the same set shown by `/scoped-models`. Pi resolves it at session start from `--models` and the `enabledModels` setting, matching `provider/modelId` or bare `modelId` patterns with minimatch. An empty list means no scope is configured and every available model is usable. Each entry is `{ model, thinkingLevel? }`; use this list when a custom model picker should mirror the built-in scope rather than enumerate the full registry.
992
1006
 
993
1007
  ### ctx.signal
994
1008
 
@@ -1188,6 +1202,8 @@ Options:
1188
1202
  - `replaceInstructions`: If true, `customInstructions` replaces the default prompt instead of being appended
1189
1203
  - `label`: Label to attach to the branch summary entry (or target entry if not summarizing)
1190
1204
 
1205
+ Like the other session-control methods, this resolves to `{ cancelled: boolean }`; cancellation comes from `session_before_tree`.
1206
+
1191
1207
  ### ctx.switchSession(sessionPath, options?)
1192
1208
 
1193
1209
  Switch to a different session file:
@@ -1233,7 +1249,7 @@ pi.registerCommand("switch", {
1233
1249
 
1234
1250
  ### Session replacement lifecycle and footguns
1235
1251
 
1236
- `withSession` receives a fresh `ReplacedSessionContext`, which extends `ExtensionCommandContext` with async `sendMessage()` and `sendUserMessage()` helpers bound to the replacement session.
1252
+ `withSession` receives a fresh `ReplacedSessionContext`, which extends `ExtensionCommandContext` with `sendMessage()` and `sendUserMessage()` helpers bound to the replacement session. Unlike the corresponding `pi` methods, both helpers return `Promise<void>`; `await` them when later work depends on delivery.
1237
1253
 
1238
1254
  Lifecycle and footguns:
1239
1255
  - `withSession` runs only after the old session has emitted `session_shutdown`, the old runtime has been torn down, the replacement session has been rebound, and the new extension instance has already received `session_start`.
@@ -1274,6 +1290,10 @@ pi.registerCommand("handoff", {
1274
1290
  });
1275
1291
  ```
1276
1292
 
1293
+ ### Stale context errors
1294
+
1295
+ After a session replacement or `await ctx.reload()`, captured `pi`, event `ctx`, and command `ctx` objects from the old runtime throw when used. This protects the replacement session from accidental writes through the old runtime. Use the `withSession` context for replacement work, treat reload as terminal for the old handler, and keep shutdown cleanup independent of session-bound APIs.
1296
+
1277
1297
  ### ctx.reload()
1278
1298
 
1279
1299
  Run the same reload flow as `/reload`.
@@ -1590,9 +1610,9 @@ Register a keyboard shortcut. See [keybindings.md](keybindings.md) for the short
1590
1610
 
1591
1611
  ```typescript
1592
1612
  pi.registerShortcut("ctrl+shift+p", {
1593
- description: "Toggle plan mode",
1613
+ description: "Open the project picker",
1594
1614
  handler: async (ctx) => {
1595
- ctx.ui.notify("Toggled!");
1615
+ ctx.ui.notify("Project picker opened!");
1596
1616
  },
1597
1617
  });
1598
1618
  ```
@@ -1602,15 +1622,15 @@ pi.registerShortcut("ctrl+shift+p", {
1602
1622
  Register a CLI flag.
1603
1623
 
1604
1624
  ```typescript
1605
- pi.registerFlag("plan", {
1606
- description: "Start in plan mode",
1607
- type: "boolean",
1608
- default: false,
1625
+ pi.registerFlag("profile", {
1626
+ description: "Start with a named profile",
1627
+ type: "string",
1609
1628
  });
1610
1629
 
1611
1630
  // Check value
1612
- if (pi.getFlag("plan")) {
1613
- // Plan mode enabled
1631
+ const profile = pi.getFlag("profile");
1632
+ if (profile) {
1633
+ // Apply the selected profile
1614
1634
  }
1615
1635
  ```
1616
1636
 
@@ -1640,7 +1660,7 @@ const all = pi.getAllTools();
1640
1660
  const builtinTools = all.filter((t) => t.sourceInfo.source === "builtin");
1641
1661
  const extensionTools = all.filter((t) => t.sourceInfo.source !== "builtin" && t.sourceInfo.source !== "sdk");
1642
1662
  pi.setActiveTools([...new Set([...active, "my_custom_tool"])]); // Keep current tools and enable my_custom_tool
1643
- pi.setActiveTools(["read", "bash"]); // Switch to read-only
1663
+ pi.setActiveTools(["read", "bash"]); // Activate only read and bash
1644
1664
  ```
1645
1665
 
1646
1666
  `pi.getAllTools()` returns `name`, `description`, `parameters`, `promptGuidelines`, and `sourceInfo`.
@@ -1791,7 +1811,7 @@ pi.registerProvider("corporate-ai", {
1791
1811
 
1792
1812
  The object form accepts a complete pi-ai `Provider`, including native `auth`, `getModels`, `refreshModels`, `filterModels`, `stream`, and `streamSimple` behavior.
1793
1813
 
1794
- **Legacy config options:**
1814
+ **Configuration options:**
1795
1815
  - `name` - Display name for the provider in UI such as `/login`.
1796
1816
  - `baseUrl` - API endpoint URL. Required when defining models.
1797
1817
  - `apiKey` - API key literal, environment interpolation (`$ENV_VAR` or `${ENV_VAR}`), or leading `!command`. Required when defining models (unless `oauth` provided). `$$` escapes `$`, and `$!` escapes a literal `!` without triggering command execution.
@@ -1951,11 +1971,40 @@ pi.registerTool({
1951
1971
  },
1952
1972
 
1953
1973
  // Optional: Custom rendering
1974
+ // rendersOwnProgress suppresses only the shell's generic Running… row.
1975
+ rendersOwnProgress: true,
1976
+ // While the result is partial, rebuild renderCall/renderResult every second.
1977
+ renderRefreshIntervalMs: 1000,
1954
1978
  renderCall(args, theme, context) { ... },
1955
1979
  renderResult(result, options, theme, context) { ... },
1956
1980
  });
1957
1981
  ```
1958
1982
 
1983
+ Use `defineTool()` when a definition is assigned to a variable or passed through an array before registration. It preserves TypeBox parameter inference that contextual `pi.registerTool({ ... })` calls already receive:
1984
+
1985
+ ```typescript
1986
+ import { defineTool } from "@astralyn/pi";
1987
+ import { Type } from "typebox";
1988
+
1989
+ const myTool = defineTool({
1990
+ name: "my_tool",
1991
+ label: "My Tool",
1992
+ description: "A typed standalone tool",
1993
+ parameters: Type.Object({ value: Type.String() }),
1994
+ async execute(_id, params) {
1995
+ return { content: [{ type: "text", text: params.value }], details: {} };
1996
+ },
1997
+ });
1998
+
1999
+ pi.registerTool(myTool);
2000
+ ```
2001
+
2002
+ **Execution mode:** `executionMode: "sequential"` makes this tool run one at a time with other tool calls. Use it for shared mutable state or a dialog that should not compete with sibling calls. `"parallel"` explicitly allows concurrent execution; when omitted, Pi uses the default execution mode.
2003
+
2004
+ **Constrained sampling:** `constrainedSampling: { type: "json_schema", strict: "prefer" }` requests provider-side schema enforcement when the active provider supports it, otherwise normal tool calling is used. Use `strict: "require"` only when the request should fail on unsupported providers. For provider-specific grammars, use `{ type: "grammar", variants: { openai_lark: "...", openai_regex: "..." } }`; each variant is optional, and unsupported providers fall back to normal function tools. `constrainedSampling: false` explicitly opts out (the same behavior as omitting it).
2005
+
2006
+ **Tool groups:** `toolGroup: "my-group"` is a freeform display identifier. Adjacent default-shell tool rows with the same identifier collapse together in the interactive transcript; it does not change execution. In the collapsed group header, `renderCall` receives `context.toolGroupSummary === true`. Tools with `renderShell: "self"` are not grouped.
2007
+
1959
2008
  **Usage accounting:** If a tool makes nested LLM calls, return their combined `Usage` as `usage`. Pi persists it on the tool result and includes it in footer, `/session`, and RPC session totals. `tool_result` handlers can inspect or replace this value.
1960
2009
 
1961
2010
  **Signaling errors:** To mark a tool execution as failed (sets `isError: true` on the result and reports it to the LLM), throw an error from `execute`. Returning a value never sets the error flag regardless of what properties you include in the return object.
@@ -2042,16 +2091,7 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
2042
2091
 
2043
2092
  **Prompt metadata:** `promptSnippet` and `promptGuidelines` are not inherited from the built-in tool. If your override should keep those prompt instructions, define them on the override explicitly.
2044
2093
 
2045
- **Your implementation must match the exact result shape**, including the `details` type. The UI and session logic depend on these shapes for rendering and state tracking.
2046
-
2047
- Built-in tool implementations:
2048
- - [read.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/read.ts) - `ReadToolDetails`
2049
- - [bash.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/bash.ts) - `BashToolDetails`
2050
- - [edit.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/edit.ts)
2051
- - [write.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/write.ts)
2052
- - [grep.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/grep.ts) - `GrepToolDetails`
2053
- - [find.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/find.ts) - `FindToolDetails`
2054
- - [ls.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/ls.ts) - `LsToolDetails`
2094
+ **Your implementation must match the exact result shape**, including the `details` type. The UI and session logic depend on these shapes for rendering and state tracking. The built-in detail types available from `@astralyn/pi` are `ReadToolDetails`, `BashToolDetails`, `EditToolDetails`, `GrepToolDetails`, `FindToolDetails`, and `LsToolDetails`.
2055
2095
 
2056
2096
  ### Remote Execution
2057
2097
 
@@ -2182,11 +2222,20 @@ export default function (pi: ExtensionAPI) {
2182
2222
 
2183
2223
  ### Custom Rendering
2184
2224
 
2185
- Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API and [tool-execution.ts](https://github.com/ming-kang/pi/blob/main/src/modes/interactive/components/tool-execution.ts) for how tool rows are composed.
2225
+ Tools can provide `renderCall` and `renderResult` for custom TUI display. See [tui.md](tui.md) for the full component API.
2186
2226
 
2187
- By default, tool output is wrapped in a `Box` that handles padding and background. A defined `renderCall` or `renderResult` must return a `Component`. If a slot renderer is not defined, `tool-execution.ts` uses fallback rendering for that slot.
2227
+ By default, tool output is wrapped in Pi's native call/result shell, which owns the status dot, result rail, padding, and fallback rendering. A defined `renderCall` or `renderResult` must return a `Component`. If a slot renderer is not defined, `tool-execution.ts` uses fallback rendering for that slot.
2188
2228
 
2189
- Set `renderShell: "self"` when the tool should render its own shell instead of using the default `Box`. 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.
2229
+ 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.
2230
+
2231
+ Two independent options control live presentation:
2232
+
2233
+ - `rendersOwnProgress: true` suppresses only the native shell's generic `Running… (Ns)` row. It does not schedule renderer updates.
2234
+ - `renderRefreshIntervalMs` periodically rebuilds `renderCall` and `renderResult` while the tool result is partial. It does not suppress generic progress.
2235
+
2236
+ Use both when a tool renders its own elapsed time, retry countdown, or similar progress UI. Refresh intervals are rounded and constrained to 250–60,000ms. The shell may rebuild sooner when another native concern needs it, so the configured interval is the maximum refresh gap rather than an exclusive cadence. Refresh stops when the result settles or the row is disposed.
2237
+
2238
+ 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.
2190
2239
 
2191
2240
  ```typescript
2192
2241
  pi.registerTool({
@@ -2210,6 +2259,8 @@ pi.registerTool({
2210
2259
  - `lastComponent` - the previously returned component for that slot, if any
2211
2260
  - `invalidate()` - request a rerender of this tool row
2212
2261
  - `toolCallId`, `cwd`, `executionStarted`, `argsComplete`, `isPartial`, `expanded`, `showImages`, `isError`
2262
+ - `result` - the current partial or final result, if one has arrived
2263
+ - `toolGroupSummary` - true while `renderCall` builds a collapsed group header
2213
2264
 
2214
2265
  Use `context.state` for cross-slot shared state. Keep slot-local caches on the returned component instance when you want to reuse and mutate the same component across renders.
2215
2266
 
@@ -2289,15 +2340,17 @@ Custom editors and `ctx.ui.custom()` components receive `keybindings: Keybinding
2289
2340
 
2290
2341
  #### Best Practices
2291
2342
 
2292
- - Use `Text` with padding `(0, 0)`. The default Box handles padding.
2343
+ - Use `Text` with padding `(0, 0)`. The native shell handles padding.
2293
2344
  - Use `\n` for multi-line content.
2294
2345
  - Handle `isPartial` for streaming progress.
2346
+ - Use `renderRefreshIntervalMs` only for values that must change without a new partial result, and compute those values from absolute time.
2347
+ - Set `rendersOwnProgress` separately when the renderer replaces the native `Running…` row.
2295
2348
  - Support `expanded` for detail on demand.
2296
2349
  - Keep default view compact.
2297
2350
  - Read `context.args` in `renderResult` instead of copying args into `context.state`.
2298
2351
  - Use `context.state` only for data that must be shared across call and result slots.
2299
2352
  - Reuse `context.lastComponent` when the same component instance can be updated in place.
2300
- - Use `renderShell: "self"` only when the default boxed shell gets in the way. In self-shell mode the tool is responsible for its own framing, padding, and background.
2353
+ - Use `renderShell: "self"` only when the native shell gets in the way. In self-shell mode the tool is responsible for its own framing, padding, and background.
2301
2354
 
2302
2355
  #### Fallback
2303
2356
 
@@ -2472,7 +2525,7 @@ const action = await ctx.ui.select(
2472
2525
  ],
2473
2526
  {
2474
2527
  subtitle: "Context now 29% full", // muted line under the title
2475
- cancelHint: "keep planning", // Esc is not destructive here
2528
+ cancelHint: "go back", // Describe what Esc actually does
2476
2529
  },
2477
2530
  );
2478
2531
 
@@ -2540,9 +2593,35 @@ if (confirmed) {
2540
2593
 
2541
2594
  See [examples/extensions/timed-confirm.ts](../examples/extensions/timed-confirm.ts) for complete examples.
2542
2595
 
2596
+ ### Terminal Input
2597
+
2598
+ `ctx.ui.onTerminalInput()` listens to raw terminal input in interactive TUI mode. It returns an unsubscribe function. Handlers run synchronously in registration order before Pi processes the input:
2599
+
2600
+ ```typescript
2601
+ let unsubscribe: (() => void) | undefined;
2602
+
2603
+ pi.on("session_start", (_event, ctx) => {
2604
+ unsubscribe?.();
2605
+ unsubscribe = ctx.ui.onTerminalInput((data) => {
2606
+ if (data === "\u0007") return { consume: true }; // Stop later handlers and Pi's input handling
2607
+ if (data === "j") return { data: "\u001b[B" }; // Rewrite for later handlers and the focused component
2608
+ return undefined; // Pass through unchanged
2609
+ });
2610
+ });
2611
+
2612
+ pi.on("session_shutdown", () => {
2613
+ unsubscribe?.();
2614
+ unsubscribe = undefined;
2615
+ });
2616
+ ```
2617
+
2618
+ Return `{ consume: true }` to stop dispatch immediately. Return `{ data }` to replace the input seen by later listeners and then Pi's focused component; an empty replacement also prevents focused-component handling after listeners finish. In RPC, JSON, and print modes this is a no-op, so guard terminal-specific behavior with `ctx.mode === "tui"`.
2619
+
2543
2620
  ### Widgets, Status, and Footer
2544
2621
 
2545
2622
  ```typescript
2623
+ import { Text } from "@earendil-works/pi-tui";
2624
+
2546
2625
  // Status in footer (persistent until cleared)
2547
2626
  ctx.ui.setStatus("my-ext", "Processing...");
2548
2627
  ctx.ui.setStatus("my-ext", undefined); // Clear
@@ -2575,11 +2654,24 @@ ctx.ui.setWidget("my-widget", (tui, theme) => new Text(theme.fg("accent", "Custo
2575
2654
  ctx.ui.setWidget("my-widget", undefined); // Clear
2576
2655
 
2577
2656
  // Custom footer (replaces built-in footer entirely)
2578
- ctx.ui.setFooter((tui, theme) => ({
2579
- render(width) { return [theme.fg("dim", "Custom footer")]; },
2657
+ ctx.ui.setFooter((_tui, theme, footerData) => ({
2658
+ render(_width) {
2659
+ const branch = footerData.getGitBranch() ?? "not a git repository";
2660
+ return [theme.fg("dim", `Custom footer: ${branch}`)];
2661
+ },
2580
2662
  invalidate() {},
2581
2663
  }));
2582
2664
  ctx.ui.setFooter(undefined); // Restore built-in footer
2665
+ // footerData also exposes getExtensionStatuses(), getAvailableProviderCount(),
2666
+ // and onBranchChange() for an invalidating custom footer.
2667
+
2668
+ // Custom startup header
2669
+ ctx.ui.setHeader((_tui, theme) => new Text(theme.fg("accent", "Project ready"), 0, 0));
2670
+ ctx.ui.setHeader(undefined); // Restore built-in header
2671
+
2672
+ // Label used for collapsed thinking blocks
2673
+ ctx.ui.setHiddenThinkingLabel("Reasoning");
2674
+ ctx.ui.setHiddenThinkingLabel(); // Restore default label
2583
2675
 
2584
2676
  // Terminal title
2585
2677
  ctx.ui.setTitle("pi - my-project");
@@ -2709,7 +2801,7 @@ if (result) {
2709
2801
  }
2710
2802
  ```
2711
2803
 
2712
- The callback receives:
2804
+ The factory may return a component directly or a `Promise` for one. The callback receives:
2713
2805
  - `tui` - TUI instance (for screen dimensions, focus management)
2714
2806
  - `theme` - Current theme for styling
2715
2807
  - `keybindings` - App keybinding manager (for checking shortcuts)
@@ -2892,87 +2984,6 @@ const highlighted = highlightCode(code, lang, theme);
2892
2984
 
2893
2985
  Use `ctx.mode === "tui"` before TUI-specific features (`custom()`, component factories, terminal input). Use `ctx.hasUI` before dialog and notification methods that work in both TUI and RPC modes.
2894
2986
 
2895
- ## Examples Reference
2896
-
2897
- All examples in [examples/extensions/](../examples/extensions/).
2898
-
2899
- | Example | Description | Key APIs |
2900
- |---------|-------------|----------|
2901
- | **Tools** |||
2902
- | `hello.ts` | Minimal tool registration | `registerTool` |
2903
- | `question.ts` | Tool with user interaction | `registerTool`, `ui.select` |
2904
- | `questionnaire.ts` | Multi-step wizard tool | `registerTool`, `ui.custom` |
2905
- | `todo.ts` | Stateful tool with persistence | `registerTool`, `appendEntry`, `renderResult`, session events |
2906
- | `dynamic-tools.ts` | Register tools after startup and during commands | `registerTool`, `session_start`, `registerCommand` |
2907
- | `structured-output.ts` | Final structured-output tool with `terminate: true` | `registerTool`, terminating tool results |
2908
- | `truncated-tool.ts` | Output truncation example | `registerTool`, `truncateHead` |
2909
- | `tool-override.ts` | Override built-in read tool | `registerTool` (same name as built-in) |
2910
- | **Commands** |||
2911
- | `pirate.ts` | Modify system prompt per-turn | `registerCommand`, `before_agent_start` |
2912
- | `summarize.ts` | Conversation summary command | `registerCommand`, `ui.custom` |
2913
- | `handoff.ts` | Cross-provider model handoff | `registerCommand`, `ui.editor`, `ui.custom` |
2914
- | `qna.ts` | Q&A with custom UI | `registerCommand`, `ui.custom`, `setEditorText` |
2915
- | `send-user-message.ts` | Inject user messages | `registerCommand`, `sendUserMessage` |
2916
- | `reload-runtime.ts` | Reload command and LLM tool handoff | `registerCommand`, `ctx.reload()`, `sendUserMessage` |
2917
- | `shutdown-command.ts` | Graceful shutdown command | `registerCommand`, `shutdown()` |
2918
- | **Events & Gates** |||
2919
- | `permission-gate.ts` | Block dangerous commands | `on("tool_call")`, `ui.confirm` |
2920
- | `project-trust.ts` | Decide or defer project trust from a user/global or CLI extension | `on("project_trust")`, trust UI, required trust result |
2921
- | `protected-paths.ts` | Block writes to specific paths | `on("tool_call")` |
2922
- | `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
2923
- | `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
2924
- | `input-transform.ts` | Transform user input | `on("input")` |
2925
- | `input-transform-streaming.ts` | Streaming-aware input transform | `on("input")`, `streamingBehavior` |
2926
- | `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
2927
- | `provider-payload.ts` | Inspect payloads and provider response headers | `on("before_provider_request")`, `on("after_provider_response")` |
2928
- | `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
2929
- | `claude-rules.ts` | Load rules from files | `on("session_start")`, `on("before_agent_start")` |
2930
- | `prompt-customizer.ts` | Add context-aware tool guidance using `systemPromptOptions` | `on("before_agent_start")`, `BuildSystemPromptOptions` |
2931
- | `file-trigger.ts` | File watcher triggers messages | `sendMessage` |
2932
- | **Compaction & Sessions** |||
2933
- | `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
2934
- | `trigger-compact.ts` | Trigger compaction manually | `compact()` |
2935
- | `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
2936
- | `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
2937
- | `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
2938
- | **UI Components** |||
2939
- | `status-line.ts` | Footer status indicator | `setStatus`, session events |
2940
- | `working-indicator.ts` | Customize the streaming working indicator | `setWorkingIndicator`, `registerCommand` |
2941
- | `github-issue-autocomplete.ts` | Add `#1234` issue completions on top of built-in autocomplete by preloading recent open issues from `gh issue list` | `addAutocompleteProvider`, `on("session_start")`, `exec` |
2942
- | `custom-footer.ts` | Replace footer entirely | `registerCommand`, `setFooter` |
2943
- | `custom-header.ts` | Replace startup header | `on("session_start")`, `setHeader` |
2944
- | `modal-editor.ts` | Vim-style modal editor | `setEditorComponent`, `CustomEditor` |
2945
- | `rainbow-editor.ts` | Custom editor styling | `setEditorComponent` |
2946
- | `widget-placement.ts` | Widget above/below editor | `setWidget` |
2947
- | `overlay-test.ts` | Overlay components | `ui.custom` with overlay options |
2948
- | `overlay-qa-tests.ts` | Comprehensive overlay tests | `ui.custom`, all overlay options |
2949
- | `notify.ts` | Simple notifications | `ui.notify` |
2950
- | `timed-confirm.ts` | Dialogs with timeout | `ui.confirm` with timeout/signal |
2951
- | `mac-system-theme.ts` | Auto-switch theme | `setTheme`, `exec` |
2952
- | **Complex Extensions** |||
2953
- | `plan-mode/` | Full plan mode implementation | All event types, `registerCommand`, `registerShortcut`, `registerFlag`, `setStatus`, `setWidget`, `sendMessage`, `setActiveTools` |
2954
- | `preset.ts` | Saveable presets (model, tools, thinking) | `registerCommand`, `registerShortcut`, `registerFlag`, `setModel`, `setActiveTools`, `setThinkingLevel`, `appendEntry` |
2955
- | `tools.ts` | Toggle tools on/off UI | `registerCommand`, `setActiveTools`, `SettingsList`, session events |
2956
- | **Remote & Sandbox** |||
2957
- | `ssh.ts` | SSH remote execution | `registerFlag`, `on("user_bash")`, `on("before_agent_start")`, tool operations |
2958
- | `interactive-shell.ts` | Persistent shell session | `on("user_bash")` |
2959
- | `sandbox/` | Sandboxed tool execution | Tool operations |
2960
- | `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM | Tool operations, built-in tool overrides, `on("user_bash")` |
2961
- | **Games** |||
2962
- | `snake.ts` | Snake game | `registerCommand`, `ui.custom`, keyboard handling |
2963
- | `space-invaders.ts` | Space Invaders game | `registerCommand`, `ui.custom` |
2964
- | `doom-overlay/` | Doom in overlay | `ui.custom` with overlay |
2965
- | **Providers** |||
2966
- | `custom-provider-anthropic/` | Custom Anthropic proxy | `registerProvider` |
2967
- | `custom-provider-gitlab-duo/` | GitLab Duo integration | `registerProvider` with OAuth |
2968
- | **Messages & Communication** |||
2969
- | `message-renderer.ts` | Custom message rendering | `registerMessageRenderer`, `sendMessage` |
2970
- | `entry-renderer.ts` | TUI-only custom entry rendering | `registerEntryRenderer`, `appendEntry` |
2971
- | `event-bus.ts` | Inter-extension events | `pi.events` |
2972
- | **Session Metadata** |||
2973
- | `session-name.ts` | Name sessions for selector | `setSessionName`, `getSessionName` |
2974
- | `bookmark.ts` | Bookmark entries for /tree | `setLabel` |
2975
- | **Misc** |||
2976
- | `inline-bash.ts` | Inline bash in tool calls | `on("tool_call")` |
2977
- | `bash-spawn-hook.ts` | Adjust bash command, cwd, and env before execution | `createBashTool`, `spawnHook` |
2978
- | `with-deps/` | Extension with npm dependencies | Package structure with `package.json` |
2987
+ ## Examples
2988
+
2989
+ The complete, maintained catalog is [examples/extensions/README.md](../examples/extensions/README.md). Use it to find a focused starting point by capability.
package/docs/index.md CHANGED
@@ -1,85 +1,29 @@
1
- # @astralyn/pi user and API documentation
1
+ # @astralyn/pi documentation
2
2
 
3
- @astralyn/pi is a minimal terminal coding harness. It is designed to stay small at the core while being extended through TypeScript extensions, skills, prompt templates, themes, and pi packages.
3
+ A task-oriented map for the installed package.
4
4
 
5
- This documentation is owned by @astralyn/pi and describes the behavior of the installed npm package, including its bundled features and public APIs. Upstream Pi documentation and release tags are used only as synchronization input; they are not the user-facing source for these docs.
5
+ ## Get started
6
6
 
7
- ## Quick start
7
+ - [Quickstart](quickstart.md) — install, authenticate, and run a first session.
8
+ - [Using Pi](usage.md) — interactive mode, CLI use, and project instructions.
9
+ - [Providers](providers.md) — subscription and API-key configuration.
8
10
 
9
- Install Pi with npm:
11
+ ## Work in a project
10
12
 
11
- ```bash
12
- npm install -g --ignore-scripts @astralyn/pi
13
- ```
13
+ - [Sessions](sessions.md) and [Compaction](compaction.md) — saved work, branches, and context management.
14
+ - [Settings](settings.md) and [Keybindings](keybindings.md) — configure Pi and its shortcuts.
15
+ - [Security](security.md) and [Containerization](containerization.md) — trust and isolation boundaries.
14
16
 
15
- `--ignore-scripts` disables dependency lifecycle scripts during install. Pi does not require install scripts for normal npm installs.
17
+ ## Bundled package features
16
18
 
17
- To uninstall the npm package:
19
+ - [Bundled features overview](bundled/README.md) — the complete shipped-feature and extension catalog.
18
20
 
19
- ```bash
20
- npm uninstall -g @astralyn/pi
21
- ```
21
+ ## Customize and integrate
22
22
 
23
- For pnpm, Yarn, or Bun installs, use the matching global remove command: `pnpm remove -g @astralyn/pi`, `yarn global remove @astralyn/pi`, or `bun uninstall -g @astralyn/pi`.
23
+ - [Extensions](extensions.md), [Skills](skills.md), [Prompt templates](prompt-templates.md), [Themes](themes.md), and [Pi packages](packages.md).
24
+ - [SDK](sdk.md), [RPC mode](rpc.md), [JSON event stream mode](json.md), and [TUI components](tui.md).
24
25
 
25
- Then run it in a project directory:
26
+ ## Platforms and reference
26
27
 
27
- ```bash
28
- pi
29
- ```
30
-
31
- Authenticate with `/login` for subscription providers, or set an API key such as `ANTHROPIC_API_KEY` before starting pi.
32
-
33
- For the full first-run flow, see [Quickstart](quickstart.md).
34
-
35
- ## Start here
36
-
37
- - [Quickstart](quickstart.md) - install, authenticate, and run a first session.
38
- - [Using Pi](usage.md) - interactive mode, slash commands, context files, and CLI reference.
39
- - [Providers](providers.md) - subscription and API-key setup for built-in providers.
40
- - [llama.cpp](llama-cpp.md) - run a local router and manage models with `/llama`.
41
- - [Security](security.md) - project trust, sandbox boundaries, and vulnerability reporting.
42
- - [Containerization](containerization.md) - sandbox pi with Gondolin, Docker, or OpenShell.
43
- - [Settings](settings.md) - global and project settings.
44
- - [Keybindings](keybindings.md) - default shortcuts and custom keybindings.
45
- - [Sessions](sessions.md) - session management, branching, and tree navigation.
46
- - [Compaction](compaction.md) - context compaction and branch summarization.
47
-
48
- ## Bundled features
49
-
50
- The installed package includes built-in extensions, themes, and native tool presentation:
51
-
52
- - [Bundled overview](bundled/README.md) - package features and how they fit together.
53
- - [Bundled extensions](bundled/extensions/README.md) - catalog and links to every bundled extension.
54
- - [Bundled themes](bundled/themes.md) - the ice-cream themes included with the package.
55
- - [Native tool presentation](bundled/tool-presentation.md) - the shared tool-call and result layout.
56
-
57
- ## Customization
58
-
59
- - [Extensions](extensions.md) - TypeScript modules for tools, commands, events, and custom UI.
60
- - [Skills](skills.md) - Agent Skills for reusable on-demand capabilities.
61
- - [Prompt templates](prompt-templates.md) - reusable prompts that expand from slash commands.
62
- - [Themes](themes.md) - built-in and custom terminal themes.
63
- - [Pi packages](packages.md) - bundle and share extensions, skills, prompts, and themes.
64
- - [Custom models](models.md) - add model entries for supported provider APIs.
65
- - [Custom providers](custom-provider.md) - implement custom APIs and OAuth flows.
66
-
67
- ## Programmatic usage
68
-
69
- - [SDK](sdk.md) - embed pi in Node.js applications.
70
- - [RPC mode](rpc.md) - integrate over stdin/stdout JSONL.
71
- - [JSON event stream mode](json.md) - print mode with structured events.
72
- - [TUI components](tui.md) - build custom terminal UI for extensions.
73
-
74
- ## Reference
75
-
76
- - [Environment variables](environment-variables.md) - Pi process configuration and session metadata available to bash tools.
77
- - [Session format](session-format.md) - JSONL session file format, entry types, and SessionManager API.
78
-
79
- ## Platform setup
80
-
81
- - [Windows](windows.md)
82
- - [Termux on Android](termux.md)
83
- - [tmux](tmux.md)
84
- - [Terminal setup](terminal-setup.md)
85
- - [Shell aliases](shell-aliases.md)
28
+ - [Windows](windows.md), [Termux](termux.md), [tmux](tmux.md), and [Terminal setup](terminal-setup.md).
29
+ - [Environment variables](environment-variables.md) and [Session format](session-format.md).
package/docs/json.md CHANGED
@@ -8,25 +8,31 @@ Outputs all session events as JSON lines to stdout. Useful for integrating pi in
8
8
 
9
9
  ## Event Types
10
10
 
11
- Events are defined in [`AgentSessionEvent`](https://github.com/ming-kang/pi/blob/main/src/core/agent-session.ts#L102):
11
+ Events are defined by `AgentSessionEvent`, exported from [`@astralyn/pi`](https://www.npmjs.com/package/@astralyn/pi):
12
12
 
13
13
  ```typescript
14
14
  type AgentSessionEvent =
15
- | AgentEvent
15
+ | Exclude<AgentEvent, { type: "agent_end" }>
16
+ | { type: "agent_end"; messages: AgentMessage[]; willRetry: boolean }
17
+ | { type: "agent_settled" }
16
18
  | { type: "queue_update"; steering: readonly string[]; followUp: readonly string[] }
17
19
  | { type: "compaction_start"; reason: "manual" | "threshold" | "overflow" }
20
+ | { type: "entry_appended"; entry: SessionEntry }
21
+ | { type: "session_info_changed"; name: string | undefined }
22
+ | { type: "thinking_level_changed"; level: ThinkingLevel }
18
23
  | { type: "compaction_end"; reason: "manual" | "threshold" | "overflow"; result: CompactionResult | undefined; aborted: boolean; willRetry: boolean; errorMessage?: string }
19
24
  | { type: "auto_retry_start"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
20
25
  | { type: "auto_retry_end"; success: boolean; attempt: number; finalError?: string }
21
26
  | { type: "summarization_retry_scheduled"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }
22
27
  | { type: "summarization_retry_attempt_start"; source: "branchSummary" }
23
28
  | { type: "summarization_retry_attempt_start"; source: "compaction"; reason: "manual" | "threshold" | "overflow" }
24
- | { type: "summarization_retry_finished" };
29
+ | { type: "summarization_retry_finished" }
30
+ | { type: "bash_execution_update"; id?: string; delta: string };
25
31
  ```
26
32
 
27
33
  `queue_update` emits the full pending steering and follow-up queues whenever they change. `compaction_start` and `compaction_end` cover both manual and automatic compaction.
28
34
 
29
- Base events from [`AgentEvent`](https://github.com/earendil-works/pi/blob/v0.82.1/packages/agent/src/types.ts#L179):
35
+ Base events retained by `AgentSessionEvent` come from `AgentEvent` in [`@earendil-works/pi-agent-core`](https://www.npmjs.com/package/@earendil-works/pi-agent-core); its `agent_end` member is replaced above:
30
36
 
31
37
  ```typescript
32
38
  type AgentEvent =
@@ -48,16 +54,16 @@ type AgentEvent =
48
54
 
49
55
  ## Message Types
50
56
 
51
- Base messages from [`packages/ai/src/types.ts`](https://github.com/earendil-works/pi/blob/v0.82.1/packages/ai/src/types.ts#L134):
52
- - `UserMessage` (line 134)
53
- - `AssistantMessage` (line 140)
54
- - `ToolResultMessage` (line 152)
57
+ Base message types come from [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai):
58
+ - `UserMessage`
59
+ - `AssistantMessage`
60
+ - `ToolResultMessage`
55
61
 
56
- Extended messages from [`src/core/messages.ts`](https://github.com/ming-kang/pi/blob/main/src/core/messages.ts#L29):
57
- - `BashExecutionMessage` (line 29)
58
- - `CustomMessage` (line 46)
59
- - `BranchSummaryMessage` (line 55)
60
- - `CompactionSummaryMessage` (line 62)
62
+ Coding-agent-specific messages are documented in [Session Format](session-format.md):
63
+ - `BashExecutionMessage`
64
+ - `CustomMessage`
65
+ - `BranchSummaryMessage`
66
+ - `CompactionSummaryMessage`
61
67
 
62
68
  ## Output Format
63
69
 
@@ -76,7 +82,7 @@ Followed by events as they occur:
76
82
  {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","delta":"Hello",...}}
77
83
  {"type":"message_end","message":{...}}
78
84
  {"type":"turn_end","message":{...},"toolResults":[]}
79
- {"type":"agent_end","messages":[...]}
85
+ {"type":"agent_end","messages":[...],"willRetry":false}
80
86
  ```
81
87
 
82
88
  ## Example