@earendil-works/pi-coding-agent 0.86.0 → 0.87.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 (138) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +37 -0
  3. package/dist/bundle/chunks/{chunk-7YM6BE7Y.js → chunk-4DKZACXI.js} +53 -46
  4. package/dist/bundle/chunks/chunk-GV2E3GBU.js +2 -0
  5. package/dist/bundle/chunks/github-copilot.js +1 -1
  6. package/dist/bundle/chunks/meta.js +2 -0
  7. package/dist/bundle/chunks/{openai-completions-KQPOPEVM.js → openai-completions-XHML6MTL.js} +1 -1
  8. package/dist/bundle/chunks/{virtual-modules-XW5APVUE.js → virtual-modules-BNWPZYDH.js} +1 -1
  9. package/dist/bundle/cli-runtime.js +3 -0
  10. package/dist/bundle/cli.js +4 -2
  11. package/dist/bundle/index.js +1 -1
  12. package/dist/bundle/rpc-entry.js +1 -1
  13. package/dist/cli/args.d.ts.map +1 -1
  14. package/dist/cli/args.js +1 -0
  15. package/dist/cli/args.js.map +1 -1
  16. package/dist/cli/file-processor.d.ts +1 -1
  17. package/dist/cli/file-processor.d.ts.map +1 -1
  18. package/dist/cli/file-processor.js.map +1 -1
  19. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  20. package/dist/core/agent-session-runtime.js +1 -1
  21. package/dist/core/agent-session-runtime.js.map +1 -1
  22. package/dist/core/agent-session.d.ts +27 -3
  23. package/dist/core/agent-session.d.ts.map +1 -1
  24. package/dist/core/agent-session.js +389 -119
  25. package/dist/core/agent-session.js.map +1 -1
  26. package/dist/core/cache-warmer.d.ts +1 -0
  27. package/dist/core/cache-warmer.d.ts.map +1 -1
  28. package/dist/core/cache-warmer.js +15 -1
  29. package/dist/core/cache-warmer.js.map +1 -1
  30. package/dist/core/compaction/compaction.d.ts +3 -1
  31. package/dist/core/compaction/compaction.d.ts.map +1 -1
  32. package/dist/core/compaction/compaction.js +146 -48
  33. package/dist/core/compaction/compaction.js.map +1 -1
  34. package/dist/core/crash-log.d.ts +5 -0
  35. package/dist/core/crash-log.d.ts.map +1 -1
  36. package/dist/core/crash-log.js +68 -0
  37. package/dist/core/crash-log.js.map +1 -1
  38. package/dist/core/export-html/template.js +6 -1
  39. package/dist/core/extensions/index.d.ts +1 -1
  40. package/dist/core/extensions/index.d.ts.map +1 -1
  41. package/dist/core/extensions/index.js.map +1 -1
  42. package/dist/core/extensions/runner.d.ts +16 -3
  43. package/dist/core/extensions/runner.d.ts.map +1 -1
  44. package/dist/core/extensions/runner.js +110 -5
  45. package/dist/core/extensions/runner.js.map +1 -1
  46. package/dist/core/extensions/types.d.ts +77 -6
  47. package/dist/core/extensions/types.d.ts.map +1 -1
  48. package/dist/core/extensions/types.js.map +1 -1
  49. package/dist/core/index.d.ts +1 -1
  50. package/dist/core/index.d.ts.map +1 -1
  51. package/dist/core/index.js.map +1 -1
  52. package/dist/core/model-config.d.ts +52 -0
  53. package/dist/core/model-config.d.ts.map +1 -1
  54. package/dist/core/model-config.js +16 -0
  55. package/dist/core/model-config.js.map +1 -1
  56. package/dist/core/model-resolver.d.ts.map +1 -1
  57. package/dist/core/model-resolver.js +1 -0
  58. package/dist/core/model-resolver.js.map +1 -1
  59. package/dist/core/prompt-templates.d.ts +6 -1
  60. package/dist/core/prompt-templates.d.ts.map +1 -1
  61. package/dist/core/prompt-templates.js +61 -35
  62. package/dist/core/prompt-templates.js.map +1 -1
  63. package/dist/core/provider-composer.d.ts +1 -0
  64. package/dist/core/provider-composer.d.ts.map +1 -1
  65. package/dist/core/provider-composer.js +19 -0
  66. package/dist/core/provider-composer.js.map +1 -1
  67. package/dist/core/resource-loader.d.ts.map +1 -1
  68. package/dist/core/resource-loader.js +6 -2
  69. package/dist/core/resource-loader.js.map +1 -1
  70. package/dist/core/sdk.d.ts.map +1 -1
  71. package/dist/core/sdk.js +3 -4
  72. package/dist/core/sdk.js.map +1 -1
  73. package/dist/core/session-manager.d.ts +36 -9
  74. package/dist/core/session-manager.d.ts.map +1 -1
  75. package/dist/core/session-manager.js +97 -7
  76. package/dist/core/session-manager.js.map +1 -1
  77. package/dist/core/tools/read.d.ts +4 -1
  78. package/dist/core/tools/read.d.ts.map +1 -1
  79. package/dist/core/tools/read.js +5 -1
  80. package/dist/core/tools/read.js.map +1 -1
  81. package/dist/index.d.ts +2 -2
  82. package/dist/index.d.ts.map +1 -1
  83. package/dist/index.js +1 -1
  84. package/dist/index.js.map +1 -1
  85. package/dist/main.d.ts.map +1 -1
  86. package/dist/main.js +4 -3
  87. package/dist/main.js.map +1 -1
  88. package/dist/modes/interactive/bug-report.d.ts +2 -0
  89. package/dist/modes/interactive/bug-report.d.ts.map +1 -1
  90. package/dist/modes/interactive/bug-report.js +6 -5
  91. package/dist/modes/interactive/bug-report.js.map +1 -1
  92. package/dist/modes/interactive/components/extension-editor.d.ts +4 -1
  93. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  94. package/dist/modes/interactive/components/extension-editor.js +7 -2
  95. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  96. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  97. package/dist/modes/interactive/components/tree-selector.js +7 -0
  98. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  99. package/dist/modes/interactive/interactive-mode.d.ts +5 -1
  100. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  101. package/dist/modes/interactive/interactive-mode.js +74 -5
  102. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  103. package/dist/utils/clipboard-image.d.ts.map +1 -1
  104. package/dist/utils/clipboard-image.js +1 -12
  105. package/dist/utils/clipboard-image.js.map +1 -1
  106. package/dist/utils/clipboard.d.ts.map +1 -1
  107. package/dist/utils/clipboard.js +74 -20
  108. package/dist/utils/clipboard.js.map +1 -1
  109. package/dist/utils/mime.d.ts.map +1 -1
  110. package/dist/utils/mime.js +1 -1
  111. package/dist/utils/mime.js.map +1 -1
  112. package/dist/utils/tool-result-images.d.ts +3 -1
  113. package/dist/utils/tool-result-images.d.ts.map +1 -1
  114. package/dist/utils/tool-result-images.js +4 -1
  115. package/dist/utils/tool-result-images.js.map +1 -1
  116. package/dist/utils/wsl.d.ts +3 -0
  117. package/dist/utils/wsl.d.ts.map +1 -0
  118. package/dist/utils/wsl.js +15 -0
  119. package/dist/utils/wsl.js.map +1 -0
  120. package/docs/compaction.md +23 -4
  121. package/docs/extensions.md +70 -6
  122. package/docs/models.md +29 -1
  123. package/docs/providers.md +8 -0
  124. package/docs/sdk.md +13 -2
  125. package/docs/session-format.md +15 -2
  126. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  127. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  128. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  129. package/examples/extensions/gondolin/package-lock.json +2 -2
  130. package/examples/extensions/gondolin/package.json +1 -1
  131. package/examples/extensions/sandbox/package-lock.json +2 -2
  132. package/examples/extensions/sandbox/package.json +1 -1
  133. package/examples/extensions/with-deps/package-lock.json +2 -2
  134. package/examples/extensions/with-deps/package.json +1 -1
  135. package/examples/plugins/pi-example-plugin/src/session.ts +3 -2
  136. package/npm-shrinkwrap.json +20 -20
  137. package/package.json +8 -8
  138. package/dist/bundle/chunks/chunk-7IOYH2SY.js +0 -2
@@ -294,7 +294,8 @@ user sends prompt ────────────────────
294
294
  │ ┌─── turn (repeats while LLM calls tools) ───┐ │
295
295
  │ │ │ │
296
296
  │ ├─► turn_start │ │
297
- │ ├─► context (can modify messages) │ │
297
+ │ ├─► context (can modify conversation messages) │
298
+ │ ├─► context_with_system (can modify the full transcript)
298
299
  │ ├─► before_provider_headers (can mutate headers) |
299
300
  │ ├─► before_provider_request (can inspect or replace payload)
300
301
  │ ├─► after_provider_response (status + headers, before stream consume)
@@ -307,9 +308,13 @@ user sends prompt ────────────────────
307
308
  │ │ └─► tool_execution_end │ │
308
309
  │ │ │ │
309
310
  │ └─► turn_end │ │
311
+ │ └─► threshold compaction before a naturally required next turn
310
312
  │ │
311
313
  ├─► agent_end │
312
- └─► agent_settled (no retry/compaction/follow-up left) │
314
+ ├─► retry backoff or final-attempt recovery (when selected)
315
+ │ └─► fresh agent_start on successful recovery │
316
+ ├─► agent_before_settle (can append entries and continue)│
317
+ └─► agent_settled (final, notification only) │
313
318
  │
314
319
  user sends another prompt ◄────────────────────────────────┘
315
320
 
@@ -567,9 +572,9 @@ The `systemPromptOptions` field gives extensions access to the same structured d
567
572
 
568
573
  Inside `before_agent_start`, `event.systemPrompt` and `ctx.getSystemPrompt()` both reflect the chained system prompt as of the current handler. Later `before_agent_start` handlers can still modify it again.
569
574
 
570
- #### agent_start / agent_end / agent_settled
575
+ #### agent_start / agent_end / agent_before_settle / agent_settled
571
576
 
572
- `agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. Use `agent_settled` for status integrations that need to know Pi will not continue running automatically.
577
+ `agent_start` fires when a low-level agent run begins. `agent_end` fires when that run ends, but Pi may still auto-retry, auto-compact and retry, or continue with queued follow-up messages. `agent_before_settle` is the final actionable boundary: it can append session entries and request one continuation. `agent_settled` is final and notification-only; use it for status integrations that need to know Pi will not continue running automatically.
573
578
 
574
579
  ```typescript
575
580
  pi.on("agent_start", async (_event, ctx) => {});
@@ -578,11 +583,28 @@ pi.on("agent_end", async (event, ctx) => {
578
583
  // event.messages - messages from this low-level run
579
584
  });
580
585
 
586
+ let addedReviewReminder = false;
587
+ pi.on("agent_before_settle", async (event, ctx) => {
588
+ if (addedReviewReminder) return;
589
+ addedReviewReminder = true;
590
+ return {
591
+ entries: [...event.entries, {
592
+ type: "custom_message",
593
+ customType: "review-reminder",
594
+ content: "Review the final diff before replying.",
595
+ display: false,
596
+ }],
597
+ continue: true,
598
+ };
599
+ });
600
+
581
601
  pi.on("agent_settled", async (_event, ctx) => {
582
- // ctx.isIdle() is true here unless another extension started a new run.
602
+ // ctx.isIdle() is true; runs requested here start after all settled handlers finish.
583
603
  });
584
604
  ```
585
605
 
606
+ If the run is aborted while `agent_before_settle` handlers are running, valid returned entries are still committed, but requested continuation is suppressed. Work requested from `agent_settled` is deferred until every settled handler completes, so notification dispatch is non-reentrant.
607
+
586
608
  #### ui_prompt_start / ui_prompt_end
587
609
 
588
610
  Notification-only lifecycle events for blocking user-facing extension UI prompts. They fire around `ctx.ui.select()`, `ctx.ui.confirm()`, `ctx.ui.input()`, `ctx.ui.editor()`, and `ctx.ui.custom()` so host/status integrations can report "waiting for user" instead of just "running".
@@ -610,11 +632,34 @@ pi.on("turn_start", async (event, ctx) => {
610
632
  // event.turnIndex, event.timestamp
611
633
  });
612
634
 
635
+ let replacedResponse = false;
613
636
  pi.on("turn_end", async (event, ctx) => {
614
637
  // event.turnIndex, event.message, event.toolResults
638
+ // event.entries contains the structural entries proposed so far.
639
+ if (replacedResponse || event.outcome !== "completed" || event.toolResults.length > 0) return;
640
+ replacedResponse = true;
641
+ return {
642
+ entries: [
643
+ ...event.entries,
644
+ { type: "context_edit", targetId: event.messageEntryId, replacement: null },
645
+ {
646
+ type: "custom_message",
647
+ customType: "replacement-instruction",
648
+ content: "Answer again using the persisted user request.",
649
+ display: false,
650
+ },
651
+ ],
652
+ continue: true,
653
+ };
615
654
  });
616
655
  ```
617
656
 
657
+ `turn_end` runs after the assistant and tool-result messages have been persisted and before the low-level `turn_end` event. Retry backoff and final-attempt recovery still happen after `agent_end`, preserving their existing lifecycle and queue ordering; `agent_before_settle` sees the repaired projection after that work completes. Boundary handlers run in extension load and registration order. Each handler sees prior proposals in `event.entries` and sees `event.context` rebuilt from them. Returning `entries` or `continue` replaces only that field; omitted fields preserve the current proposal. Allowed draft entry types are `custom`, `custom_message`, `context_edit`, and `compaction`. The complete proposal is validated before it is appended in list order after all handlers finish; a handler error is reported and later handlers still run. Validation prevents partially applied semantic errors, but persistence is not transactional.
658
+
659
+ `continue: true` ensures one next provider request for that boundary invocation. If tool results, steering, or a follow-up already cause that request, they satisfy the decision and no additional request is made; otherwise Pi makes one context-only request. Error and aborted responses remain hard exits. `continue: false` never suppresses natural work. Guard continuation conditions: an unconditional `continue: true` is evaluated again after the next response and can create an endless loop. A `custom_message` draft contributes a user-role model message but is extension-authored: it does not run human input hooks, slash commands, skills, or prompt templates.
660
+
661
+ Host integrations that construct `TurnEndEvent` values must now provide `messageEntryId`, `toolResultEntryIds`, `outcome`, `entries`, `continue`, and `context`. `ExtensionEvent` exhaustive switches must also handle `agent_before_settle`. `ExtensionRunner.emit()` excludes actionable turn boundaries; dispatch `turn_end` and `agent_before_settle` through `emitBoundary(baseEvent, buildContext)` so handlers receive chained previews. Other dedicated runner methods still return results for events such as `session_before_*`.
662
+
618
663
  #### message_start / message_update / message_end
619
664
 
620
665
  Fired for message lifecycle updates.
@@ -681,12 +726,31 @@ Fired before each LLM call. Modify messages non-destructively. See [Session Form
681
726
 
682
727
  ```typescript
683
728
  pi.on("context", async (event, ctx) => {
684
- // event.messages - deep copy, safe to modify
729
+ // event.messages - deep copy without system messages, safe to modify
685
730
  const filtered = event.messages.filter(m => !shouldPrune(m));
686
731
  return { messages: filtered };
687
732
  });
688
733
  ```
689
734
 
735
+ `event.messages` holds the conversation without system messages. The prompt and tool declarations belong to Pi and are not part of this hook: when the handler returns a changed list, Pi replays the current prompt sections and tool declarations into one leading system message ahead of the returned messages. Filtering, windowing, or slicing from a compaction summary therefore cannot drop the prompt or the tools. An unchanged list keeps mid-conversation system messages in place, so models that accept them retain their cached prefix. System messages a handler adds are kept after Pi's head. To change the prompt or the tool set durably, use [`before_agent_start`](#before_agent_start) or `pi.setActiveTools()`; to edit system messages for one request, use [`context_with_system`](#context_with_system).
736
+
737
+ #### context_with_system
738
+
739
+ Fired before each LLM call, after every `context` handler has run and Pi has restored the prompt and tool state. `event.messages` is the full transcript, including the leading system message and any mid-conversation prompt or tool patches (see [Session Format](session-format.md#sessionmessageentry)). The returned messages are sent as they are: this hook owns the prompt and tool declarations for the request.
740
+
741
+ ```typescript
742
+ import { getCurrentSystemMessage } from "@earendil-works/pi-ai";
743
+
744
+ pi.on("context_with_system", async (event, ctx) => {
745
+ const cut = findCutIndex(event.messages);
746
+ // Fold the dropped prefix so its prompt and tool state survives as the new head.
747
+ const head = getCurrentSystemMessage(event.messages.slice(0, cut));
748
+ return { messages: head ? [head, ...event.messages.slice(cut)] : event.messages.slice(cut) };
749
+ });
750
+ ```
751
+
752
+ Rules: keep a system message at index 0 (providers read the prompt and initial tool declarations there; Pi reports an error if a handler drops it). Removing a system message removes the tool declarations and section patches it carries. Check your output with `getCurrentSystemPrompt()` and `getCurrentTools()` from `@earendil-works/pi-ai`. Handlers run in extension load order; a `systemPrompt` forced from `before_agent_start` is still projected onto the request afterwards.
753
+
690
754
  #### before_provider_headers
691
755
 
692
756
  Fired after the outgoing HTTP headers are assembled. Use it to add, override, or remove request headers.
package/docs/models.md CHANGED
@@ -205,6 +205,7 @@ If your command is slow, expensive, rate-limited, or should keep using a previou
205
205
  | `reasoning` | No | `false` | Supports extended thinking |
206
206
  | `thinkingLevelMap` | No | omitted | Maps pi thinking levels to provider values and marks unsupported levels (see below) |
207
207
  | `input` | No | `["text"]` | Input types: `["text"]` or `["text", "image"]` |
208
+ | `inputLimits` | No | omitted | Request limits and image preprocessing for this model (see below) |
208
209
  | `contextWindow` | No | `128000` | Context window size in tokens |
209
210
  | `maxTokens` | No | `16384` | Maximum output tokens |
210
211
  | `samplingParams` | No | omitted | Sampling parameters merged verbatim into every request body (see below) |
@@ -238,6 +239,33 @@ Current behavior:
238
239
  - `/model`, `--list-models`, and the interactive footer display entries by model `id`.
239
240
  - The configured `name` is used for model matching and secondary model detail text. It does not replace the footer/status-bar model id.
240
241
 
242
+ ### Image Input Limits
243
+
244
+ Use `inputLimits.images.resize` to configure how new images are encoded before they enter conversation history:
245
+
246
+ ```json
247
+ {
248
+ "id": "vision-model",
249
+ "input": ["text", "image"],
250
+ "inputLimits": {
251
+ "images": {
252
+ "resize": {
253
+ "maxWidth": 1568,
254
+ "maxHeight": 1568,
255
+ "maxBytes": 524288,
256
+ "jpegQuality": 75
257
+ }
258
+ }
259
+ }
260
+ }
261
+ ```
262
+
263
+ `maxBytes` is the maximum base64-encoded payload size. Omitted resize fields use pi's conservative defaults: 2000×2000, 4.5 MiB encoded, and JPEG quality 80. Built-in vision models carry that profile explicitly so unknown gateways never receive larger images than before.
264
+
265
+ Pi applies the selected model's resize profile to `@file` attachments, the `read` tool, and images returned by tools. Images are encoded once before they enter history; changing models does not rewrite historical images or invalidate the cached conversation prefix. The `images.autoResize` setting can disable resizing globally.
266
+
267
+ The catalog can also record `inputLimits.maxRequestBytes`, `images.maxPerMessage`, and `images.maxPerRequest`. These fields describe hard provider limits; this initial implementation does not yet rewrite or reject conversation history based on them.
268
+
241
269
  ### Prompt Cache Lifetimes
242
270
 
243
271
  `promptCache` states how long the provider keeps a prompt cache entry alive for each retention tier pi can request (`short` is the default tier; `long` is used when `PI_CACHE_RETENTION=long`). Values are seconds and are estimates: providers publish ranges, so pick the conservative end.
@@ -374,7 +402,7 @@ Use `modelOverrides` to customize built-in models and matching extension-registe
374
402
  }
375
403
  ```
376
404
 
377
- `modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `cost` (partial), `promptCache` (merged per tier), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
405
+ `modelOverrides` supports these fields per model: `name`, `reasoning`, `thinkingLevelMap`, `input`, `inputLimits` (deep-merged), `cost` (partial), `promptCache` (merged per tier), `contextWindow`, `maxTokens`, `samplingParams` (merged per key), `headers`, `compat`.
378
406
 
379
407
  Use a `promptCache` override to enable cache warming through a proxy whose backing cache you know, for example OpenRouter routed to Anthropic:
380
408
 
package/docs/providers.md CHANGED
@@ -20,6 +20,7 @@ Use `/login` in interactive mode, then select a provider:
20
20
  - Claude Pro/Max
21
21
  - GitHub Copilot
22
22
  - xAI (Grok/X subscription)
23
+ - Meta (Muse subscription)
23
24
  - OpenRouter (OAuth-minted API key billed from OpenRouter credits)
24
25
  - Radius
25
26
 
@@ -44,6 +45,12 @@ Anthropic subscription auth is active for Claude Pro/Max accounts. Third-party h
44
45
  - Run `/login xai`, then select **Use a subscription**
45
46
  - `XAI_API_KEY` remains available through **Use an API key**
46
47
 
48
+ ### Meta (Muse subscription)
49
+
50
+ - Run `/login meta`, then select **Sign in with Meta** to open the device authorization flow
51
+ - The login mints a Model API key that is re-minted automatically about once a day
52
+ - `META_API_KEY` remains available through **Use an API key**
53
+
47
54
  ### OpenRouter
48
55
 
49
56
  - Run `/login openrouter`, then select **Sign in with OpenRouter** to open the OpenRouter PKCE authorization flow
@@ -94,6 +101,7 @@ pi
94
101
  | Together AI | `TOGETHER_API_KEY` | `together` |
95
102
  | Baseten | `BASETEN_API_KEY` | `baseten` |
96
103
  | Kimi For Coding | `KIMI_API_KEY` | `kimi-coding` |
104
+ | Meta | `META_API_KEY` | `meta` |
97
105
  | MiniMax | `MINIMAX_API_KEY` | `minimax` |
98
106
  | MiniMax (China) | `MINIMAX_CN_API_KEY` | `minimax-cn` |
99
107
  | Qwen Token Plan (existing catalog) | `QWEN_TOKEN_PLAN_API_KEY` | `qwen-token-plan` |
package/docs/sdk.md CHANGED
@@ -91,6 +91,8 @@ interface AgentSession {
91
91
 
92
92
  // State access
93
93
  agent: Agent;
94
+ sessionManager: SessionManager;
95
+ refreshContext(): void;
94
96
  model: Model | undefined;
95
97
  thinkingLevel: ThinkingLevel;
96
98
  messages: AgentMessage[];
@@ -251,8 +253,8 @@ const state = session.agent.state;
251
253
  // state.streamingMessage?: AgentMessage - current partial assistant message
252
254
  // state.errorMessage?: string - latest assistant error
253
255
 
254
- // Replace messages (useful for branching or restoration)
255
- session.agent.state.messages = messages; // copies the top-level array
256
+ // Model-visible messages are projected from session.sessionManager.
257
+ // agent.state.messages is a refreshed inspection cache; do not assign it for restoration.
256
258
 
257
259
  // Replace tools
258
260
  session.agent.state.tools = tools; // copies the top-level array
@@ -261,6 +263,15 @@ session.agent.state.tools = tools; // copies the top-level array
261
263
  await session.agent.waitForIdle();
262
264
  ```
263
265
 
266
+ Provider requests use `session.sessionManager` as the canonical finalized context. Assigning `session.agent.state.messages` does not replace persisted context and may be overwritten at the next request boundary. Restore externally stored history when constructing the session instead:
267
+
268
+ ```typescript
269
+ const restoredManager = SessionManager.inMemory(process.cwd(), { id: sessionId }, entries);
270
+ const { session } = await createAgentSession({ sessionManager: restoredManager });
271
+ ```
272
+
273
+ For an existing session, use `session.navigateTree(entryId)` to move its active branch. Use `session.sessionManager.appendMessage(...)` plus `session.refreshContext()` only when intentionally appending externally managed entries.
274
+
264
275
  ### Events
265
276
 
266
277
  Subscribe to events to receive streaming output and lifecycle notifications.
@@ -274,7 +274,7 @@ Created when context is compacted. Stores a summary of earlier messages and a co
274
274
  {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000,"systemMessage":{"role":"system","content":"You are a coding assistant.","toolsAdded":[],"timestamp":1733235000000}}
275
275
  ```
276
276
 
277
- `firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, Pi replaces older summarized entries with the compaction summary and keeps the range beginning at this entry.
277
+ `firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, Pi replaces older summarized entries with the compaction summary and keeps the range beginning at this entry. A retain-none compaction stores its own ID in this field, so no preceding entries are retained.
278
278
 
279
279
  Optional fields:
280
280
  - `systemMessage`: The replayed prompt sections and tool declarations at the compaction boundary; it becomes the leading system message of the compacted context, and system messages among the kept entries are dropped in its favor. It is absent on older session entries.
@@ -282,6 +282,16 @@ Optional fields:
282
282
  - `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
283
283
  - `fromHook`: `true` if generated by an extension, `false`/`undefined` if pi-generated (legacy field name)
284
284
 
285
+ ### ContextEditEntry
286
+
287
+ Append-only edit of one earlier context-producing entry. It changes only future model context; the target entry and its metadata remain unchanged in raw history, UI, exports, and session accounting.
288
+
289
+ ```json
290
+ {"type":"context_edit","id":"g6h7i8j9","parentId":"f6g7h8i9","timestamp":"2024-12-03T14:11:00.000Z","targetId":"c3d4e5f6","replacement":null}
291
+ ```
292
+
293
+ Targets may be user, assistant, tool-result, or custom-message entries. `replacement: null` omits the target from model context. A non-null `replacement` replaces only the target message content. String replacements for assistant and tool-result entries are normalized to one text block because those roles require content arrays. If several edits target the same entry, the latest edit on the active branch wins. Edits are branch-relative: navigating to a point before the edit reveals the target's original contribution again.
294
+
285
295
  ### BranchSummaryEntry
286
296
 
287
297
  Created when switching branches via `/tree` with an LLM generated summary of the left branch up to the common ancestor. Captures context from the abandoned path.
@@ -366,7 +376,9 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
366
376
  - Includes entries after the compaction entry
367
377
  3. Preserves non-message entries in the selected range so interactive mode can render them
368
378
 
369
- `buildSessionContext()` builds on that entry list to produce the message list for the LLM:
379
+ `buildSessionProjection()` then applies the latest `context_edit` for each selected target. It returns the model-visible messages together with their source entries. Omitted targets produce no message; replacements retain the source entry's role and metadata while changing only content. The raw selected entries are not modified.
380
+
381
+ `buildSessionContext()` builds on that projection to produce the message list for the LLM:
370
382
 
371
383
  1. Extracts current model and thinking level settings from the full path
372
384
  2. Converts selected entries to messages:
@@ -374,6 +386,7 @@ Entries normally form one tree, but navigation APIs can create multiple roots:
374
386
  - `compaction` -> complete system checkpoint followed by `compactionSummary`
375
387
  - `branch_summary` -> `branchSummary`
376
388
  - `custom_message` -> `CustomMessage`
389
+ - `context_edit` -> no context message of its own
377
390
  - `usage` and `custom` -> no context message
378
391
 
379
392
  The compaction summary replaces entries before `firstKeptEntryId`. Pre-compaction system messages are folded into the complete checkpoint rather than replayed from the retained range. Retained non-system entries and all entries after the compaction remain available to the LLM.
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-custom-provider",
9
- "version": "0.86.0",
9
+ "version": "0.87.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sdk": "^0.52.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-anthropic",
3
3
  "private": true,
4
- "version": "0.86.0",
4
+ "version": "0.87.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-custom-provider-gitlab-duo",
3
3
  "private": true,
4
- "version": "0.86.0",
4
+ "version": "0.87.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-gondolin",
9
- "version": "0.86.0",
9
+ "version": "0.87.0",
10
10
  "dependencies": {
11
11
  "@earendil-works/gondolin": "0.12.0"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-gondolin",
3
3
  "private": true,
4
- "version": "0.86.0",
4
+ "version": "0.87.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-sandbox",
9
- "version": "1.16.0",
9
+ "version": "1.17.0",
10
10
  "dependencies": {
11
11
  "@anthropic-ai/sandbox-runtime": "^0.0.26"
12
12
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-sandbox",
3
3
  "private": true,
4
- "version": "1.16.0",
4
+ "version": "1.17.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "pi-extension-with-deps",
9
- "version": "0.86.0",
9
+ "version": "0.87.0",
10
10
  "dependencies": {
11
11
  "ms": "^2.1.3"
12
12
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "pi-extension-with-deps",
3
3
  "private": true,
4
- "version": "0.86.0",
4
+ "version": "0.87.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "clean": "echo 'nothing to clean'",
@@ -16,8 +16,9 @@ export default defineFacet({
16
16
  },
17
17
  });
18
18
  env.onActivate(() => {
19
- workerActivations.state.count += 1;
20
- workerActivations.publish(BACKGROUND_CONTEXT);
19
+ workerActivations.change(BACKGROUND_CONTEXT, (draft) => {
20
+ draft.count += 1;
21
+ });
21
22
  });
22
23
  },
23
24
  });
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-coding-agent",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@earendil-works/pi-coding-agent",
9
- "version": "0.86.0",
9
+ "version": "0.87.0",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@earendil-works/chord": "^0.86.0",
13
- "@earendil-works/pi-agent-core": "^0.86.0",
14
- "@earendil-works/pi-ai": "^0.86.0",
15
- "@earendil-works/pi-tui": "^0.86.0",
12
+ "@earendil-works/chord": "^0.87.0",
13
+ "@earendil-works/pi-agent-core": "^0.87.0",
14
+ "@earendil-works/pi-ai": "^0.87.0",
15
+ "@earendil-works/pi-tui": "^0.87.0",
16
16
  "@silvia-odwyer/photon-node": "0.3.4",
17
17
  "chalk": "6.0.0",
18
18
  "cross-spawn": "7.0.6",
@@ -408,8 +408,8 @@
408
408
  }
409
409
  },
410
410
  "node_modules/@earendil-works/chord": {
411
- "version": "0.86.0",
412
- "resolved": "https://registry.npmjs.org/@earendil-works/chord/-/chord-0.86.0.tgz",
411
+ "version": "0.87.0",
412
+ "resolved": "https://registry.npmjs.org/@earendil-works/chord/-/chord-0.87.0.tgz",
413
413
  "license": "MIT",
414
414
  "dependencies": {
415
415
  "esbuild": "0.28.2"
@@ -419,13 +419,13 @@
419
419
  }
420
420
  },
421
421
  "node_modules/@earendil-works/pi-agent-core": {
422
- "version": "0.86.0",
423
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.86.0.tgz",
422
+ "version": "0.87.0",
423
+ "resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.87.0.tgz",
424
424
  "license": "MIT",
425
425
  "dependencies": {
426
- "@earendil-works/chord": "^0.86.0",
427
- "@earendil-works/pi-ai": "^0.86.0",
428
- "@earendil-works/pi-telemetry": "^0.86.0",
426
+ "@earendil-works/chord": "^0.87.0",
427
+ "@earendil-works/pi-ai": "^0.87.0",
428
+ "@earendil-works/pi-telemetry": "^0.87.0",
429
429
  "diff": "8.0.4",
430
430
  "ignore": "7.0.8",
431
431
  "typebox": "1.3.27",
@@ -436,13 +436,13 @@
436
436
  }
437
437
  },
438
438
  "node_modules/@earendil-works/pi-ai": {
439
- "version": "0.86.0",
440
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.86.0.tgz",
439
+ "version": "0.87.0",
440
+ "resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.87.0.tgz",
441
441
  "license": "MIT",
442
442
  "dependencies": {
443
443
  "@anthropic-ai/sdk": "0.124.0",
444
444
  "@aws-sdk/client-bedrock-runtime": "3.1127.0",
445
- "@earendil-works/pi-telemetry": "^0.86.0",
445
+ "@earendil-works/pi-telemetry": "^0.87.0",
446
446
  "@google/genai": "2.21.0",
447
447
  "@smithy/node-http-handler": "4.12.1",
448
448
  "http-proxy-agent": "9.1.0",
@@ -482,16 +482,16 @@
482
482
  }
483
483
  },
484
484
  "node_modules/@earendil-works/pi-telemetry": {
485
- "version": "0.86.0",
486
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.86.0.tgz",
485
+ "version": "0.87.0",
486
+ "resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.87.0.tgz",
487
487
  "license": "MIT",
488
488
  "engines": {
489
489
  "node": ">=22.19.0"
490
490
  }
491
491
  },
492
492
  "node_modules/@earendil-works/pi-tui": {
493
- "version": "0.86.0",
494
- "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.86.0.tgz",
493
+ "version": "0.87.0",
494
+ "resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.87.0.tgz",
495
495
  "license": "MIT",
496
496
  "dependencies": {
497
497
  "get-east-asian-width": "1.6.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-coding-agent",
3
- "version": "0.86.0",
3
+ "version": "0.87.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -49,10 +49,10 @@
49
49
  "prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
50
50
  },
51
51
  "dependencies": {
52
- "@earendil-works/chord": "^0.86.0",
53
- "@earendil-works/pi-agent-core": "^0.86.0",
54
- "@earendil-works/pi-ai": "^0.86.0",
55
- "@earendil-works/pi-tui": "^0.86.0",
52
+ "@earendil-works/chord": "^0.87.0",
53
+ "@earendil-works/pi-agent-core": "^0.87.0",
54
+ "@earendil-works/pi-ai": "^0.87.0",
55
+ "@earendil-works/pi-tui": "^0.87.0",
56
56
  "@silvia-odwyer/photon-node": "0.3.4",
57
57
  "chalk": "6.0.0",
58
58
  "cross-spawn": "7.0.6",
@@ -73,9 +73,9 @@
73
73
  "protobufjs": "7.6.6"
74
74
  },
75
75
  "devDependencies": {
76
- "@earendil-works/pi-client": "^0.86.0",
77
- "@earendil-works/pi-protocol": "^0.86.0",
78
- "@earendil-works/pi-server": "^0.86.0",
76
+ "@earendil-works/pi-client": "^0.87.0",
77
+ "@earendil-works/pi-protocol": "^0.87.0",
78
+ "@earendil-works/pi-server": "^0.87.0",
79
79
  "@types/cross-spawn": "6.0.6",
80
80
  "@types/hosted-git-info": "3.0.5",
81
81
  "@types/node": "22.19.19",
@@ -1,2 +0,0 @@
1
- import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
- import{AgentSession,AgentSessionRuntime,ArminComponent,AssistantMessageComponent,BashExecutionComponent,BorderedLoader,BranchSummaryMessageComponent,CONFIG_DIR_NAME,CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent,Container,CredentialSynchronizationError,CustomEditor,CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES,DefaultPackageManager,DefaultResourceLoader,DynamicBorder,ExtensionEditorComponent,ExtensionInputComponent,ExtensionRunner,ExtensionSelectorComponent,FooterComponent,InteractiveMode,LoginDialogComponent,ModelRegistry,ModelRuntime,ModelSelectorComponent,OAuthSelectorComponent,ProjectTrustStore,RpcClient,SelectList,SessionManager,SessionSelectorComponent,SettingsManager,SettingsSelectorComponent,SkillInvocationMessageComponent,Theme,ThinkingSelectorComponent,ToolExecutionComponent,TreeSelectorComponent,UserMessageComponent,UserMessageSelectorComponent,VERSION,buildContextEntries,buildSessionContext,calculateContextTokens,collectEntriesForBranchSummary,compact,convertToLlm,convertToPng,copyToClipboard,createAgentSession,createAgentSessionFromServices,createAgentSessionRuntime,createAgentSessionServices,createBashTool,createBashToolDefinition,createCodingTools,createEditTool,createEditToolDefinition,createEventBus,createExtensionRuntime,createFindTool,createFindToolDefinition,createGrepTool,createGrepToolDefinition,createLocalBashOperations,createLocalPowerShellOperations,createLsTool,createLsToolDefinition,createPowerShellTool,createPowerShellToolDefinition,createReadOnlyTools,createReadTool,createReadToolDefinition,createSyntheticSourceInfo,createWriteTool,createWriteToolDefinition,defineTool,detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions,estimateTokens,findCutPoint,findTurnStartIndex,formatDimensionNote,formatSize,formatSkillsForPrompt,generateBranchSummary,generateDiffString,generateSummary,generateSummaryWithUsage,generateUnifiedPatch,getAgentDir,getAvailableThemes,getDocsPath,getExamplesPath,getLanguageFromPath,getLastAssistantUsage,getLatestCompactionEntry,getMarkdownTheme,getPackageDir,getPowerShellConfig,getReadmePath,getSelectListTheme,getSettingsListTheme,getShellConfig,hasTrustRequiringProjectResources,highlightCode,initTheme,isBashToolResult,isEditToolResult,isFindToolResult,isGrepToolResult,isLsToolResult,isPowerShellToolResult,isReadToolResult,isToolCallEventType,isWriteToolResult,keyHint,keyText,loadProjectContextFiles,loadSkills,loadSkillsFromDir,main,migrateSessionEntries,parseArgs,parseFrontmatter,parseSessionEntries,parseSkillBlock,prepareBranchEntries,rawKeyHint,readStoredCredential,renderDiff,resizeImage,resolveCliModel,resolveModelScopeWithDiagnostics,runPrintMode,runRpcMode,serializeConversation,sessionEntryToContextMessages,shouldCompact,stripFrontmatter,truncateHead,truncateLine,truncateTail,truncateToVisualLines,withFileMutationQueue,wrapRegisteredTool,wrapRegisteredTools}from"./chunk-7YM6BE7Y.js";import{__export}from"./chunk-4L3WN2XY.js";var dist_exports={};__export(dist_exports,{AgentSession:()=>AgentSession,AgentSessionRuntime:()=>AgentSessionRuntime,ArminComponent:()=>ArminComponent,AssistantMessageComponent:()=>AssistantMessageComponent,BashExecutionComponent:()=>BashExecutionComponent,BorderedLoader:()=>BorderedLoader,BranchSummaryMessageComponent:()=>BranchSummaryMessageComponent,CONFIG_DIR_NAME:()=>CONFIG_DIR_NAME,CURRENT_SESSION_VERSION:()=>CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent:()=>CompactionSummaryMessageComponent,CredentialSynchronizationError:()=>CredentialSynchronizationError,CustomEditor:()=>CustomEditor,CustomMessageComponent:()=>CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS:()=>DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES:()=>DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES:()=>DEFAULT_MAX_LINES,DefaultPackageManager:()=>DefaultPackageManager,DefaultResourceLoader:()=>DefaultResourceLoader,DynamicBorder:()=>DynamicBorder,ExtensionEditorComponent:()=>ExtensionEditorComponent,ExtensionInputComponent:()=>ExtensionInputComponent,ExtensionRunner:()=>ExtensionRunner,ExtensionSelectorComponent:()=>ExtensionSelectorComponent,FooterComponent:()=>FooterComponent,InteractiveMode:()=>InteractiveMode,LoginDialogComponent:()=>LoginDialogComponent,ModelRegistry:()=>ModelRegistry,ModelRuntime:()=>ModelRuntime,ModelSelectorComponent:()=>ModelSelectorComponent,OAuthSelectorComponent:()=>OAuthSelectorComponent,ProjectTrustStore:()=>ProjectTrustStore,RpcClient:()=>RpcClient,SessionManager:()=>SessionManager,SessionSelectorComponent:()=>SessionSelectorComponent,SettingsManager:()=>SettingsManager,SettingsSelectorComponent:()=>SettingsSelectorComponent,ShowImagesSelectorComponent:()=>ShowImagesSelectorComponent,SkillInvocationMessageComponent:()=>SkillInvocationMessageComponent,Theme:()=>Theme,ThemeSelectorComponent:()=>ThemeSelectorComponent,ThinkingSelectorComponent:()=>ThinkingSelectorComponent,ToolExecutionComponent:()=>ToolExecutionComponent,TreeSelectorComponent:()=>TreeSelectorComponent,UserMessageComponent:()=>UserMessageComponent,UserMessageSelectorComponent:()=>UserMessageSelectorComponent,VERSION:()=>VERSION,buildContextEntries:()=>buildContextEntries,buildSessionContext:()=>buildSessionContext,calculateContextTokens:()=>calculateContextTokens,collectEntriesForBranchSummary:()=>collectEntriesForBranchSummary,compact:()=>compact,convertToLlm:()=>convertToLlm,convertToPng:()=>convertToPng,copyToClipboard:()=>copyToClipboard,createAgentSession:()=>createAgentSession,createAgentSessionFromServices:()=>createAgentSessionFromServices,createAgentSessionRuntime:()=>createAgentSessionRuntime,createAgentSessionServices:()=>createAgentSessionServices,createBashTool:()=>createBashTool,createBashToolDefinition:()=>createBashToolDefinition,createCodingTools:()=>createCodingTools,createEditTool:()=>createEditTool,createEditToolDefinition:()=>createEditToolDefinition,createEventBus:()=>createEventBus,createExtensionRuntime:()=>createExtensionRuntime,createFindTool:()=>createFindTool,createFindToolDefinition:()=>createFindToolDefinition,createGrepTool:()=>createGrepTool,createGrepToolDefinition:()=>createGrepToolDefinition,createLocalBashOperations:()=>createLocalBashOperations,createLocalPowerShellOperations:()=>createLocalPowerShellOperations,createLsTool:()=>createLsTool,createLsToolDefinition:()=>createLsToolDefinition,createPowerShellTool:()=>createPowerShellTool,createPowerShellToolDefinition:()=>createPowerShellToolDefinition,createReadOnlyTools:()=>createReadOnlyTools,createReadTool:()=>createReadTool,createReadToolDefinition:()=>createReadToolDefinition,createSyntheticSourceInfo:()=>createSyntheticSourceInfo,createWriteTool:()=>createWriteTool,createWriteToolDefinition:()=>createWriteToolDefinition,defineTool:()=>defineTool,detectSupportedImageMimeTypeFromFile:()=>detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions:()=>discoverAndLoadExtensions,estimateTokens:()=>estimateTokens,findCutPoint:()=>findCutPoint,findTurnStartIndex:()=>findTurnStartIndex,formatDimensionNote:()=>formatDimensionNote,formatSize:()=>formatSize,formatSkillsForPrompt:()=>formatSkillsForPrompt,generateBranchSummary:()=>generateBranchSummary,generateDiffString:()=>generateDiffString,generateSummary:()=>generateSummary,generateSummaryWithUsage:()=>generateSummaryWithUsage,generateUnifiedPatch:()=>generateUnifiedPatch,getAgentDir:()=>getAgentDir,getDocsPath:()=>getDocsPath,getExamplesPath:()=>getExamplesPath,getLanguageFromPath:()=>getLanguageFromPath,getLastAssistantUsage:()=>getLastAssistantUsage,getLatestCompactionEntry:()=>getLatestCompactionEntry,getMarkdownTheme:()=>getMarkdownTheme,getPackageDir:()=>getPackageDir,getPowerShellConfig:()=>getPowerShellConfig,getReadmePath:()=>getReadmePath,getSelectListTheme:()=>getSelectListTheme,getSettingsListTheme:()=>getSettingsListTheme,getShellConfig:()=>getShellConfig,hasTrustRequiringProjectResources:()=>hasTrustRequiringProjectResources,highlightCode:()=>highlightCode,initTheme:()=>initTheme,isBashToolResult:()=>isBashToolResult,isEditToolResult:()=>isEditToolResult,isFindToolResult:()=>isFindToolResult,isGrepToolResult:()=>isGrepToolResult,isLsToolResult:()=>isLsToolResult,isPowerShellToolResult:()=>isPowerShellToolResult,isReadToolResult:()=>isReadToolResult,isToolCallEventType:()=>isToolCallEventType,isWriteToolResult:()=>isWriteToolResult,keyHint:()=>keyHint,keyText:()=>keyText,loadProjectContextFiles:()=>loadProjectContextFiles,loadSkills:()=>loadSkills,loadSkillsFromDir:()=>loadSkillsFromDir,main:()=>main,migrateSessionEntries:()=>migrateSessionEntries,parseArgs:()=>parseArgs,parseFrontmatter:()=>parseFrontmatter,parseSessionEntries:()=>parseSessionEntries,parseSkillBlock:()=>parseSkillBlock,prepareBranchEntries:()=>prepareBranchEntries,rawKeyHint:()=>rawKeyHint,readStoredCredential:()=>readStoredCredential,renderDiff:()=>renderDiff,resizeImage:()=>resizeImage,resolveCliModel:()=>resolveCliModel,resolveModelScopeWithDiagnostics:()=>resolveModelScopeWithDiagnostics,runPrintMode:()=>runPrintMode,runRpcMode:()=>runRpcMode,serializeConversation:()=>serializeConversation,sessionEntryToContextMessages:()=>sessionEntryToContextMessages,shouldCompact:()=>shouldCompact,stripFrontmatter:()=>stripFrontmatter,truncateHead:()=>truncateHead,truncateLine:()=>truncateLine,truncateTail:()=>truncateTail,truncateToVisualLines:()=>truncateToVisualLines,withFileMutationQueue:()=>withFileMutationQueue,wrapRegisteredTool:()=>wrapRegisteredTool,wrapRegisteredTools:()=>wrapRegisteredTools});var SHOW_IMAGES_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ShowImagesSelectorComponent=class extends Container{selectList;constructor(currentValue,onSelect,onCancel){super();let items=[{value:"yes",label:"Yes",description:"Show images inline in terminal"},{value:"no",label:"No",description:"Show text placeholder instead"}];this.addChild(new DynamicBorder),this.selectList=new SelectList(items,5,getSelectListTheme(),SHOW_IMAGES_SELECT_LIST_LAYOUT),this.selectList.setSelectedIndex(currentValue?0:1),this.selectList.onSelect=item=>{onSelect(item.value==="yes")},this.selectList.onCancel=()=>{onCancel()},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};var THEME_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ThemeSelectorComponent=class extends Container{selectList;onPreview;constructor(currentTheme,onSelect,onCancel,onPreview){super(),this.onPreview=onPreview;let themes=getAvailableThemes(),themeItems=themes.map(name=>({value:name,label:name,description:name===currentTheme?"(current)":void 0}));this.addChild(new DynamicBorder),this.selectList=new SelectList(themeItems,10,getSelectListTheme(),THEME_SELECT_LIST_LAYOUT);let currentIndex=themes.indexOf(currentTheme);currentIndex!==-1&&this.selectList.setSelectedIndex(currentIndex),this.selectList.onSelect=item=>{onSelect(item.value)},this.selectList.onCancel=()=>{onCancel()},this.selectList.onSelectionChange=item=>{this.onPreview(item.value)},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};export{ShowImagesSelectorComponent,ThemeSelectorComponent,dist_exports};