@astralyn/pi 0.82.7 → 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 (127) hide show
  1. package/CHANGELOG.md +34 -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/core/agent-session-runtime.d.ts.map +1 -1
  11. package/dist/core/agent-session-runtime.js +3 -0
  12. package/dist/core/agent-session-runtime.js.map +1 -1
  13. package/dist/core/agent-session.d.ts +1 -1
  14. package/dist/core/agent-session.d.ts.map +1 -1
  15. package/dist/core/agent-session.js +13 -6
  16. package/dist/core/agent-session.js.map +1 -1
  17. package/dist/core/extensions/runner.d.ts +1 -0
  18. package/dist/core/extensions/runner.d.ts.map +1 -1
  19. package/dist/core/extensions/runner.js +7 -0
  20. package/dist/core/extensions/runner.js.map +1 -1
  21. package/dist/core/extensions/types.d.ts +7 -0
  22. package/dist/core/extensions/types.d.ts.map +1 -1
  23. package/dist/core/extensions/types.js.map +1 -1
  24. package/dist/core/footer-data-provider.d.ts +10 -0
  25. package/dist/core/footer-data-provider.d.ts.map +1 -1
  26. package/dist/core/footer-data-provider.js +1 -1
  27. package/dist/core/footer-data-provider.js.map +1 -1
  28. package/dist/core/model-runtime.d.ts +2 -0
  29. package/dist/core/model-runtime.d.ts.map +1 -1
  30. package/dist/core/model-runtime.js.map +1 -1
  31. package/dist/core/package-manager.d.ts.map +1 -1
  32. package/dist/core/package-manager.js +13 -6
  33. package/dist/core/package-manager.js.map +1 -1
  34. package/dist/core/resource-loader.d.ts +15 -0
  35. package/dist/core/resource-loader.d.ts.map +1 -1
  36. package/dist/core/resource-loader.js +70 -9
  37. package/dist/core/resource-loader.js.map +1 -1
  38. package/dist/core/tools/find.d.ts.map +1 -1
  39. package/dist/core/tools/find.js +34 -4
  40. package/dist/core/tools/find.js.map +1 -1
  41. package/dist/core/trust-manager.d.ts.map +1 -1
  42. package/dist/core/trust-manager.js +48 -9
  43. package/dist/core/trust-manager.js.map +1 -1
  44. package/dist/extensions/index.d.ts.map +1 -1
  45. package/dist/extensions/index.js +0 -2
  46. package/dist/extensions/index.js.map +1 -1
  47. package/dist/extensions/llama/provider.d.ts.map +1 -1
  48. package/dist/extensions/llama/provider.js +1 -1
  49. package/dist/extensions/llama/provider.js.map +1 -1
  50. package/dist/main.d.ts.map +1 -1
  51. package/dist/main.js +43 -0
  52. package/dist/main.js.map +1 -1
  53. package/dist/modes/interactive/components/extension-selector.d.ts +1 -1
  54. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  55. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  56. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  57. package/dist/modes/interactive/components/model-selector.js +4 -1
  58. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  59. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  60. package/dist/modes/interactive/external-editor.js +40 -3
  61. package/dist/modes/interactive/external-editor.js.map +1 -1
  62. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  63. package/dist/modes/interactive/interactive-mode.js +20 -6
  64. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  65. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  66. package/dist/modes/rpc/rpc-mode.js +13 -0
  67. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  68. package/dist/utils/paths.d.ts +2 -3
  69. package/dist/utils/paths.d.ts.map +1 -1
  70. package/dist/utils/paths.js +2 -3
  71. package/dist/utils/paths.js.map +1 -1
  72. package/docs/bundled/README.md +13 -16
  73. package/docs/bundled/themes.md +1 -1
  74. package/docs/compaction.md +25 -30
  75. package/docs/custom-provider.md +298 -583
  76. package/docs/docs.json +0 -8
  77. package/docs/extensions.md +112 -116
  78. package/docs/index.md +18 -74
  79. package/docs/json.md +20 -14
  80. package/docs/models.md +193 -151
  81. package/docs/providers.md +2 -1
  82. package/docs/quickstart.md +3 -3
  83. package/docs/rpc.md +165 -123
  84. package/docs/sdk.md +119 -178
  85. package/docs/security.md +1 -1
  86. package/docs/session-format.md +139 -119
  87. package/docs/skills.md +0 -1
  88. package/docs/themes.md +2 -2
  89. package/docs/tui.md +411 -549
  90. package/docs/usage.md +3 -11
  91. package/examples/README.md +6 -1
  92. package/examples/extensions/README.md +13 -33
  93. package/examples/extensions/custom-provider-anthropic/index.ts +9 -3
  94. package/examples/extensions/dynamic-resources/dynamic.json +1 -1
  95. package/examples/extensions/truncated-tool.ts +2 -2
  96. package/examples/sdk/12-full-control.ts +2 -0
  97. package/npm-shrinkwrap.json +21 -21
  98. package/package.json +5 -5
  99. package/dist/extensions/plan/constants.d.ts +0 -68
  100. package/dist/extensions/plan/constants.d.ts.map +0 -1
  101. package/dist/extensions/plan/constants.js +0 -100
  102. package/dist/extensions/plan/constants.js.map +0 -1
  103. package/dist/extensions/plan/index.d.ts +0 -30
  104. package/dist/extensions/plan/index.d.ts.map +0 -1
  105. package/dist/extensions/plan/index.js +0 -429
  106. package/dist/extensions/plan/index.js.map +0 -1
  107. package/dist/extensions/plan/schema.d.ts +0 -20
  108. package/dist/extensions/plan/schema.d.ts.map +0 -1
  109. package/dist/extensions/plan/schema.js +0 -13
  110. package/dist/extensions/plan/schema.js.map +0 -1
  111. package/dist/extensions/plan/state.d.ts +0 -38
  112. package/dist/extensions/plan/state.d.ts.map +0 -1
  113. package/dist/extensions/plan/state.js +0 -96
  114. package/dist/extensions/plan/state.js.map +0 -1
  115. package/dist/extensions/plan/storage.d.ts +0 -26
  116. package/dist/extensions/plan/storage.d.ts.map +0 -1
  117. package/dist/extensions/plan/storage.js +0 -83
  118. package/dist/extensions/plan/storage.js.map +0 -1
  119. package/dist/extensions/plan/view.d.ts +0 -44
  120. package/dist/extensions/plan/view.d.ts.map +0 -1
  121. package/dist/extensions/plan/view.js +0 -149
  122. package/dist/extensions/plan/view.js.map +0 -1
  123. package/docs/bundled/extensions/README.md +0 -19
  124. package/docs/bundled/extensions/plan.md +0 -34
  125. package/examples/extensions/plan-mode/README.md +0 -66
  126. package/examples/extensions/plan-mode/index.ts +0 -390
  127. 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
 
@@ -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.
@@ -1960,6 +1980,31 @@ pi.registerTool({
1960
1980
  });
1961
1981
  ```
1962
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
+
1963
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.
1964
2009
 
1965
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.
@@ -2046,16 +2091,7 @@ See [examples/extensions/tool-override.ts](../examples/extensions/tool-override.
2046
2091
 
2047
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.
2048
2093
 
2049
- **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.
2050
-
2051
- Built-in tool implementations:
2052
- - [read.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/read.ts) - `ReadToolDetails`
2053
- - [bash.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/bash.ts) - `BashToolDetails`
2054
- - [edit.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/edit.ts)
2055
- - [write.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/write.ts)
2056
- - [grep.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/grep.ts) - `GrepToolDetails`
2057
- - [find.ts](https://github.com/ming-kang/pi/blob/main/src/core/tools/find.ts) - `FindToolDetails`
2058
- - [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`.
2059
2095
 
2060
2096
  ### Remote Execution
2061
2097
 
@@ -2186,7 +2222,7 @@ export default function (pi: ExtensionAPI) {
2186
2222
 
2187
2223
  ### Custom Rendering
2188
2224
 
2189
- 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.
2190
2226
 
2191
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.
2192
2228
 
@@ -2223,6 +2259,8 @@ pi.registerTool({
2223
2259
  - `lastComponent` - the previously returned component for that slot, if any
2224
2260
  - `invalidate()` - request a rerender of this tool row
2225
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
2226
2264
 
2227
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.
2228
2266
 
@@ -2487,7 +2525,7 @@ const action = await ctx.ui.select(
2487
2525
  ],
2488
2526
  {
2489
2527
  subtitle: "Context now 29% full", // muted line under the title
2490
- cancelHint: "keep planning", // Esc is not destructive here
2528
+ cancelHint: "go back", // Describe what Esc actually does
2491
2529
  },
2492
2530
  );
2493
2531
 
@@ -2555,9 +2593,35 @@ if (confirmed) {
2555
2593
 
2556
2594
  See [examples/extensions/timed-confirm.ts](../examples/extensions/timed-confirm.ts) for complete examples.
2557
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
+
2558
2620
  ### Widgets, Status, and Footer
2559
2621
 
2560
2622
  ```typescript
2623
+ import { Text } from "@earendil-works/pi-tui";
2624
+
2561
2625
  // Status in footer (persistent until cleared)
2562
2626
  ctx.ui.setStatus("my-ext", "Processing...");
2563
2627
  ctx.ui.setStatus("my-ext", undefined); // Clear
@@ -2590,11 +2654,24 @@ ctx.ui.setWidget("my-widget", (tui, theme) => new Text(theme.fg("accent", "Custo
2590
2654
  ctx.ui.setWidget("my-widget", undefined); // Clear
2591
2655
 
2592
2656
  // Custom footer (replaces built-in footer entirely)
2593
- ctx.ui.setFooter((tui, theme) => ({
2594
- 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
+ },
2595
2662
  invalidate() {},
2596
2663
  }));
2597
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
2598
2675
 
2599
2676
  // Terminal title
2600
2677
  ctx.ui.setTitle("pi - my-project");
@@ -2724,7 +2801,7 @@ if (result) {
2724
2801
  }
2725
2802
  ```
2726
2803
 
2727
- The callback receives:
2804
+ The factory may return a component directly or a `Promise` for one. The callback receives:
2728
2805
  - `tui` - TUI instance (for screen dimensions, focus management)
2729
2806
  - `theme` - Current theme for styling
2730
2807
  - `keybindings` - App keybinding manager (for checking shortcuts)
@@ -2907,87 +2984,6 @@ const highlighted = highlightCode(code, lang, theme);
2907
2984
 
2908
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.
2909
2986
 
2910
- ## Examples Reference
2911
-
2912
- All examples in [examples/extensions/](../examples/extensions/).
2913
-
2914
- | Example | Description | Key APIs |
2915
- |---------|-------------|----------|
2916
- | **Tools** |||
2917
- | `hello.ts` | Minimal tool registration | `registerTool` |
2918
- | `question.ts` | Tool with user interaction | `registerTool`, `ui.select` |
2919
- | `questionnaire.ts` | Multi-step wizard tool | `registerTool`, `ui.custom` |
2920
- | `todo.ts` | Stateful tool with persistence | `registerTool`, `appendEntry`, `renderResult`, session events |
2921
- | `dynamic-tools.ts` | Register tools after startup and during commands | `registerTool`, `session_start`, `registerCommand` |
2922
- | `structured-output.ts` | Final structured-output tool with `terminate: true` | `registerTool`, terminating tool results |
2923
- | `truncated-tool.ts` | Output truncation example | `registerTool`, `truncateHead` |
2924
- | `tool-override.ts` | Override built-in read tool | `registerTool` (same name as built-in) |
2925
- | **Commands** |||
2926
- | `pirate.ts` | Modify system prompt per-turn | `registerCommand`, `before_agent_start` |
2927
- | `summarize.ts` | Conversation summary command | `registerCommand`, `ui.custom` |
2928
- | `handoff.ts` | Cross-provider model handoff | `registerCommand`, `ui.editor`, `ui.custom` |
2929
- | `qna.ts` | Q&A with custom UI | `registerCommand`, `ui.custom`, `setEditorText` |
2930
- | `send-user-message.ts` | Inject user messages | `registerCommand`, `sendUserMessage` |
2931
- | `reload-runtime.ts` | Reload command and LLM tool handoff | `registerCommand`, `ctx.reload()`, `sendUserMessage` |
2932
- | `shutdown-command.ts` | Graceful shutdown command | `registerCommand`, `shutdown()` |
2933
- | **Events & Gates** |||
2934
- | `permission-gate.ts` | Block dangerous commands | `on("tool_call")`, `ui.confirm` |
2935
- | `project-trust.ts` | Decide or defer project trust from a user/global or CLI extension | `on("project_trust")`, trust UI, required trust result |
2936
- | `protected-paths.ts` | Block writes to specific paths | `on("tool_call")` |
2937
- | `confirm-destructive.ts` | Confirm session changes | `on("session_before_switch")`, `on("session_before_fork")` |
2938
- | `dirty-repo-guard.ts` | Warn on dirty git repo | `on("session_before_*")`, `exec` |
2939
- | `input-transform.ts` | Transform user input | `on("input")` |
2940
- | `input-transform-streaming.ts` | Streaming-aware input transform | `on("input")`, `streamingBehavior` |
2941
- | `model-status.ts` | React to model changes | `on("model_select")`, `setStatus` |
2942
- | `provider-payload.ts` | Inspect payloads and provider response headers | `on("before_provider_request")`, `on("after_provider_response")` |
2943
- | `system-prompt-header.ts` | Display system prompt info | `on("agent_start")`, `getSystemPrompt` |
2944
- | `claude-rules.ts` | Load rules from files | `on("session_start")`, `on("before_agent_start")` |
2945
- | `prompt-customizer.ts` | Add context-aware tool guidance using `systemPromptOptions` | `on("before_agent_start")`, `BuildSystemPromptOptions` |
2946
- | `file-trigger.ts` | File watcher triggers messages | `sendMessage` |
2947
- | **Compaction & Sessions** |||
2948
- | `custom-compaction.ts` | Custom compaction summary | `on("session_before_compact")` |
2949
- | `trigger-compact.ts` | Trigger compaction manually | `compact()` |
2950
- | `git-checkpoint.ts` | Git stash on turns | `on("turn_start")`, `on("session_before_fork")`, `exec` |
2951
- | `git-merge-and-resolve.ts` | Fetch, merge, and resolve conflicts | `on("agent_end")`, `exec`, `sendUserMessage` |
2952
- | `auto-commit-on-exit.ts` | Commit on shutdown | `on("session_shutdown")`, `exec` |
2953
- | **UI Components** |||
2954
- | `status-line.ts` | Footer status indicator | `setStatus`, session events |
2955
- | `working-indicator.ts` | Customize the streaming working indicator | `setWorkingIndicator`, `registerCommand` |
2956
- | `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` |
2957
- | `custom-footer.ts` | Replace footer entirely | `registerCommand`, `setFooter` |
2958
- | `custom-header.ts` | Replace startup header | `on("session_start")`, `setHeader` |
2959
- | `modal-editor.ts` | Vim-style modal editor | `setEditorComponent`, `CustomEditor` |
2960
- | `rainbow-editor.ts` | Custom editor styling | `setEditorComponent` |
2961
- | `widget-placement.ts` | Widget above/below editor | `setWidget` |
2962
- | `overlay-test.ts` | Overlay components | `ui.custom` with overlay options |
2963
- | `overlay-qa-tests.ts` | Comprehensive overlay tests | `ui.custom`, all overlay options |
2964
- | `notify.ts` | Simple notifications | `ui.notify` |
2965
- | `timed-confirm.ts` | Dialogs with timeout | `ui.confirm` with timeout/signal |
2966
- | `mac-system-theme.ts` | Auto-switch theme | `setTheme`, `exec` |
2967
- | **Complex Extensions** |||
2968
- | `plan-mode/` | Full plan mode implementation | All event types, `registerCommand`, `registerShortcut`, `registerFlag`, `setStatus`, `setWidget`, `sendMessage`, `setActiveTools` |
2969
- | `preset.ts` | Saveable presets (model, tools, thinking) | `registerCommand`, `registerShortcut`, `registerFlag`, `setModel`, `setActiveTools`, `setThinkingLevel`, `appendEntry` |
2970
- | `tools.ts` | Toggle tools on/off UI | `registerCommand`, `setActiveTools`, `SettingsList`, session events |
2971
- | **Remote & Sandbox** |||
2972
- | `ssh.ts` | SSH remote execution | `registerFlag`, `on("user_bash")`, `on("before_agent_start")`, tool operations |
2973
- | `interactive-shell.ts` | Persistent shell session | `on("user_bash")` |
2974
- | `sandbox/` | Sandboxed tool execution | Tool operations |
2975
- | `gondolin/` | Route built-in tools and `!` commands into a Gondolin micro-VM | Tool operations, built-in tool overrides, `on("user_bash")` |
2976
- | **Games** |||
2977
- | `snake.ts` | Snake game | `registerCommand`, `ui.custom`, keyboard handling |
2978
- | `space-invaders.ts` | Space Invaders game | `registerCommand`, `ui.custom` |
2979
- | `doom-overlay/` | Doom in overlay | `ui.custom` with overlay |
2980
- | **Providers** |||
2981
- | `custom-provider-anthropic/` | Custom Anthropic proxy | `registerProvider` |
2982
- | `custom-provider-gitlab-duo/` | GitLab Duo integration | `registerProvider` with OAuth |
2983
- | **Messages & Communication** |||
2984
- | `message-renderer.ts` | Custom message rendering | `registerMessageRenderer`, `sendMessage` |
2985
- | `entry-renderer.ts` | TUI-only custom entry rendering | `registerEntryRenderer`, `appendEntry` |
2986
- | `event-bus.ts` | Inter-extension events | `pi.events` |
2987
- | **Session Metadata** |||
2988
- | `session-name.ts` | Name sessions for selector | `setSessionName`, `getSessionName` |
2989
- | `bookmark.ts` | Bookmark entries for /tree | `setLabel` |
2990
- | **Misc** |||
2991
- | `inline-bash.ts` | Inline bash in tool calls | `on("tool_call")` |
2992
- | `bash-spawn-hook.ts` | Adjust bash command, cwd, and env before execution | `createBashTool`, `spawnHook` |
2993
- | `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