@code-yeongyu/senpi 2026.6.28-4 → 2026.6.30-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +2 -1
  3. package/dist/core/agent-session.d.ts +2 -0
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +54 -28
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/extensions/builtin/hooks/command-runner.d.ts +25 -0
  8. package/dist/core/extensions/builtin/hooks/command-runner.d.ts.map +1 -0
  9. package/dist/core/extensions/builtin/hooks/command-runner.js +152 -0
  10. package/dist/core/extensions/builtin/hooks/command-runner.js.map +1 -0
  11. package/dist/core/extensions/builtin/hooks/command.d.ts +11 -0
  12. package/dist/core/extensions/builtin/hooks/command.d.ts.map +1 -0
  13. package/dist/core/extensions/builtin/hooks/command.js +180 -0
  14. package/dist/core/extensions/builtin/hooks/command.js.map +1 -0
  15. package/dist/core/extensions/builtin/hooks/config-loader.d.ts +19 -0
  16. package/dist/core/extensions/builtin/hooks/config-loader.d.ts.map +1 -0
  17. package/dist/core/extensions/builtin/hooks/config-loader.js +125 -0
  18. package/dist/core/extensions/builtin/hooks/config-loader.js.map +1 -0
  19. package/dist/core/extensions/builtin/hooks/diagnostics.d.ts +10 -0
  20. package/dist/core/extensions/builtin/hooks/diagnostics.d.ts.map +1 -0
  21. package/dist/core/extensions/builtin/hooks/diagnostics.js +14 -0
  22. package/dist/core/extensions/builtin/hooks/diagnostics.js.map +1 -0
  23. package/dist/core/extensions/builtin/hooks/dispatcher.d.ts +60 -0
  24. package/dist/core/extensions/builtin/hooks/dispatcher.d.ts.map +1 -0
  25. package/dist/core/extensions/builtin/hooks/dispatcher.js +161 -0
  26. package/dist/core/extensions/builtin/hooks/dispatcher.js.map +1 -0
  27. package/dist/core/extensions/builtin/hooks/handler.d.ts +12 -0
  28. package/dist/core/extensions/builtin/hooks/handler.d.ts.map +1 -0
  29. package/dist/core/extensions/builtin/hooks/handler.js +128 -0
  30. package/dist/core/extensions/builtin/hooks/handler.js.map +1 -0
  31. package/dist/core/extensions/builtin/hooks/index.d.ts +6 -0
  32. package/dist/core/extensions/builtin/hooks/index.d.ts.map +1 -0
  33. package/dist/core/extensions/builtin/hooks/index.js +216 -0
  34. package/dist/core/extensions/builtin/hooks/index.js.map +1 -0
  35. package/dist/core/extensions/builtin/hooks/lifecycle-adapter.d.ts +29 -0
  36. package/dist/core/extensions/builtin/hooks/lifecycle-adapter.d.ts.map +1 -0
  37. package/dist/core/extensions/builtin/hooks/lifecycle-adapter.js +276 -0
  38. package/dist/core/extensions/builtin/hooks/lifecycle-adapter.js.map +1 -0
  39. package/dist/core/extensions/builtin/hooks/matcher.d.ts +7 -0
  40. package/dist/core/extensions/builtin/hooks/matcher.d.ts.map +1 -0
  41. package/dist/core/extensions/builtin/hooks/matcher.js +109 -0
  42. package/dist/core/extensions/builtin/hooks/matcher.js.map +1 -0
  43. package/dist/core/extensions/builtin/hooks/output-bounds.d.ts +29 -0
  44. package/dist/core/extensions/builtin/hooks/output-bounds.d.ts.map +1 -0
  45. package/dist/core/extensions/builtin/hooks/output-bounds.js +47 -0
  46. package/dist/core/extensions/builtin/hooks/output-bounds.js.map +1 -0
  47. package/dist/core/extensions/builtin/hooks/output-parser.d.ts +27 -0
  48. package/dist/core/extensions/builtin/hooks/output-parser.d.ts.map +1 -0
  49. package/dist/core/extensions/builtin/hooks/output-parser.js +168 -0
  50. package/dist/core/extensions/builtin/hooks/output-parser.js.map +1 -0
  51. package/dist/core/extensions/builtin/hooks/plugin-loader.d.ts +11 -0
  52. package/dist/core/extensions/builtin/hooks/plugin-loader.d.ts.map +1 -0
  53. package/dist/core/extensions/builtin/hooks/plugin-loader.js +138 -0
  54. package/dist/core/extensions/builtin/hooks/plugin-loader.js.map +1 -0
  55. package/dist/core/extensions/builtin/hooks/plugin-manifest.d.ts +47 -0
  56. package/dist/core/extensions/builtin/hooks/plugin-manifest.d.ts.map +1 -0
  57. package/dist/core/extensions/builtin/hooks/plugin-manifest.js +86 -0
  58. package/dist/core/extensions/builtin/hooks/plugin-manifest.js.map +1 -0
  59. package/dist/core/extensions/builtin/hooks/prompt-adapter.d.ts +30 -0
  60. package/dist/core/extensions/builtin/hooks/prompt-adapter.d.ts.map +1 -0
  61. package/dist/core/extensions/builtin/hooks/prompt-adapter.js +59 -0
  62. package/dist/core/extensions/builtin/hooks/prompt-adapter.js.map +1 -0
  63. package/dist/core/extensions/builtin/hooks/safety.d.ts +14 -0
  64. package/dist/core/extensions/builtin/hooks/safety.d.ts.map +1 -0
  65. package/dist/core/extensions/builtin/hooks/safety.js +179 -0
  66. package/dist/core/extensions/builtin/hooks/safety.js.map +1 -0
  67. package/dist/core/extensions/builtin/hooks/schema.d.ts +3 -0
  68. package/dist/core/extensions/builtin/hooks/schema.d.ts.map +1 -0
  69. package/dist/core/extensions/builtin/hooks/schema.js +94 -0
  70. package/dist/core/extensions/builtin/hooks/schema.js.map +1 -0
  71. package/dist/core/extensions/builtin/hooks/stop-adapter.d.ts +18 -0
  72. package/dist/core/extensions/builtin/hooks/stop-adapter.d.ts.map +1 -0
  73. package/dist/core/extensions/builtin/hooks/stop-adapter.js +282 -0
  74. package/dist/core/extensions/builtin/hooks/stop-adapter.js.map +1 -0
  75. package/dist/core/extensions/builtin/hooks/tool-adapter.d.ts +11 -0
  76. package/dist/core/extensions/builtin/hooks/tool-adapter.d.ts.map +1 -0
  77. package/dist/core/extensions/builtin/hooks/tool-adapter.js +158 -0
  78. package/dist/core/extensions/builtin/hooks/tool-adapter.js.map +1 -0
  79. package/dist/core/extensions/builtin/hooks/trust-storage.d.ts +24 -0
  80. package/dist/core/extensions/builtin/hooks/trust-storage.d.ts.map +1 -0
  81. package/dist/core/extensions/builtin/hooks/trust-storage.js +102 -0
  82. package/dist/core/extensions/builtin/hooks/trust-storage.js.map +1 -0
  83. package/dist/core/extensions/builtin/hooks/trust.d.ts +34 -0
  84. package/dist/core/extensions/builtin/hooks/trust.d.ts.map +1 -0
  85. package/dist/core/extensions/builtin/hooks/trust.js +194 -0
  86. package/dist/core/extensions/builtin/hooks/trust.js.map +1 -0
  87. package/dist/core/extensions/builtin/hooks/types.d.ts +134 -0
  88. package/dist/core/extensions/builtin/hooks/types.d.ts.map +1 -0
  89. package/dist/core/extensions/builtin/hooks/types.js +36 -0
  90. package/dist/core/extensions/builtin/hooks/types.js.map +1 -0
  91. package/dist/core/extensions/builtin/index.d.ts.map +1 -1
  92. package/dist/core/extensions/builtin/index.js +2 -0
  93. package/dist/core/extensions/builtin/index.js.map +1 -1
  94. package/dist/core/extensions/index.d.ts +1 -1
  95. package/dist/core/extensions/index.d.ts.map +1 -1
  96. package/dist/core/extensions/index.js.map +1 -1
  97. package/dist/core/extensions/runner.d.ts +5 -0
  98. package/dist/core/extensions/runner.d.ts.map +1 -1
  99. package/dist/core/extensions/runner.js +20 -1
  100. package/dist/core/extensions/runner.js.map +1 -1
  101. package/dist/core/extensions/types.d.ts +25 -1
  102. package/dist/core/extensions/types.d.ts.map +1 -1
  103. package/dist/core/extensions/types.js.map +1 -1
  104. package/dist/core/http-dispatcher.d.ts.map +1 -1
  105. package/dist/core/http-dispatcher.js +28 -1
  106. package/dist/core/http-dispatcher.js.map +1 -1
  107. package/dist/core/package-manager.d.ts +1 -0
  108. package/dist/core/package-manager.d.ts.map +1 -1
  109. package/dist/core/package-manager.js +14 -1
  110. package/dist/core/package-manager.js.map +1 -1
  111. package/dist/core/resource-loader.d.ts +14 -1
  112. package/dist/core/resource-loader.d.ts.map +1 -1
  113. package/dist/core/resource-loader.js +38 -0
  114. package/dist/core/resource-loader.js.map +1 -1
  115. package/dist/core/settings-manager.d.ts +5 -0
  116. package/dist/core/settings-manager.d.ts.map +1 -1
  117. package/dist/core/settings-manager.js +8 -0
  118. package/dist/core/settings-manager.js.map +1 -1
  119. package/dist/index.d.ts +2 -2
  120. package/dist/index.d.ts.map +1 -1
  121. package/dist/index.js.map +1 -1
  122. package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  123. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  124. package/dist/modes/interactive/components/assistant-message.js +15 -7
  125. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  126. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  127. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  128. package/dist/modes/interactive/components/settings-selector.js +13 -1
  129. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  130. package/dist/modes/interactive/components/status-indicator.d.ts +27 -0
  131. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
  132. package/dist/modes/interactive/components/status-indicator.js +64 -0
  133. package/dist/modes/interactive/components/status-indicator.js.map +1 -0
  134. package/dist/modes/interactive/components/user-message.d.ts +6 -2
  135. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  136. package/dist/modes/interactive/components/user-message.js +15 -4
  137. package/dist/modes/interactive/components/user-message.js.map +1 -1
  138. package/dist/modes/interactive/interactive-mode.d.ts +9 -12
  139. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  140. package/dist/modes/interactive/interactive-mode.js +123 -125
  141. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  142. package/dist/modes/rpc/rpc-client.d.ts +15 -0
  143. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  144. package/dist/modes/rpc/rpc-client.js +14 -0
  145. package/dist/modes/rpc/rpc-client.js.map +1 -1
  146. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  147. package/dist/modes/rpc/rpc-mode.js +16 -0
  148. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  149. package/dist/modes/rpc/rpc-types.d.ts +26 -0
  150. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  151. package/dist/modes/rpc/rpc-types.js.map +1 -1
  152. package/dist/utils/version-check.d.ts +1 -0
  153. package/dist/utils/version-check.d.ts.map +1 -1
  154. package/dist/utils/version-check.js +7 -0
  155. package/dist/utils/version-check.js.map +1 -1
  156. package/docs/extensions.md +464 -0
  157. package/docs/index.md +1 -1
  158. package/docs/packages.md +9 -6
  159. package/docs/rpc.md +58 -0
  160. package/docs/settings.md +1 -0
  161. package/examples/extensions/README.md +1 -0
  162. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  163. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  164. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  165. package/examples/extensions/gondolin/package-lock.json +2 -2
  166. package/examples/extensions/gondolin/package.json +1 -1
  167. package/examples/extensions/sandbox/package-lock.json +2 -2
  168. package/examples/extensions/sandbox/package.json +1 -1
  169. package/examples/extensions/with-deps/package-lock.json +2 -2
  170. package/examples/extensions/with-deps/package.json +1 -1
  171. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts +3 -1
  172. package/node_modules/@earendil-works/pi-agent-core/dist/agent.d.ts.map +1 -1
  173. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js +9 -1
  174. package/node_modules/@earendil-works/pi-agent-core/dist/agent.js.map +1 -1
  175. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  176. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.d.ts.map +1 -1
  177. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js +2 -14
  178. package/node_modules/@earendil-works/pi-ai/dist/api/azure-openai-responses.js.map +1 -1
  179. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.d.ts.map +1 -1
  180. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js +12 -4
  181. package/node_modules/@earendil-works/pi-ai/dist/api/bedrock-converse-stream.js.map +1 -1
  182. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.d.ts.map +1 -1
  183. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js +2 -1
  184. package/node_modules/@earendil-works/pi-ai/dist/api/google-generative-ai.js.map +1 -1
  185. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.d.ts.map +1 -1
  186. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js +2 -1
  187. package/node_modules/@earendil-works/pi-ai/dist/api/google-vertex.js.map +1 -1
  188. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.d.ts.map +1 -1
  189. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js +10 -24
  190. package/node_modules/@earendil-works/pi-ai/dist/api/openai-codex-responses.js.map +1 -1
  191. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.d.ts.map +1 -1
  192. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js +8 -3
  193. package/node_modules/@earendil-works/pi-ai/dist/api/openai-completions.js.map +1 -1
  194. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.d.ts.map +1 -1
  195. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js +2 -14
  196. package/node_modules/@earendil-works/pi-ai/dist/api/openai-responses.js.map +1 -1
  197. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.d.ts.map +1 -1
  198. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js +2 -1
  199. package/node_modules/@earendil-works/pi-ai/dist/api/openrouter-images.js.map +1 -1
  200. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts +15 -45
  201. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  202. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +15 -45
  203. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  204. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts +167 -32
  205. package/node_modules/@earendil-works/pi-ai/dist/models.generated.d.ts.map +1 -1
  206. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts +119 -0
  207. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.d.ts.map +1 -1
  208. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js +119 -0
  209. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.models.js.map +1 -1
  210. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts +20 -0
  211. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.d.ts.map +1 -1
  212. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js +18 -0
  213. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.models.js.map +1 -1
  214. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js +1 -1
  215. package/node_modules/@earendil-works/pi-ai/dist/providers/groq.models.js.map +1 -1
  216. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js +3 -3
  217. package/node_modules/@earendil-works/pi-ai/dist/providers/opencode-go.models.js.map +1 -1
  218. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts +8 -32
  219. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.d.ts.map +1 -1
  220. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js +46 -65
  221. package/node_modules/@earendil-works/pi-ai/dist/providers/openrouter.models.js.map +1 -1
  222. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts +20 -0
  223. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.d.ts.map +1 -1
  224. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js +18 -0
  225. package/node_modules/@earendil-works/pi-ai/dist/providers/vercel-ai-gateway.models.js.map +1 -1
  226. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js +12 -12
  227. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-ams.models.js.map +1 -1
  228. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js +12 -12
  229. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-cn.models.js.map +1 -1
  230. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js +12 -12
  231. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi-token-plan-sgp.models.js.map +1 -1
  232. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js +15 -15
  233. package/node_modules/@earendil-works/pi-ai/dist/providers/xiaomi.models.js.map +1 -1
  234. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +25 -0
  235. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -0
  236. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +109 -0
  237. package/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -0
  238. package/node_modules/@earendil-works/pi-ai/package.json +1 -1
  239. package/node_modules/@earendil-works/pi-tui/dist/tui.d.ts.map +1 -1
  240. package/node_modules/@earendil-works/pi-tui/dist/tui.js +3 -0
  241. package/node_modules/@earendil-works/pi-tui/dist/tui.js.map +1 -1
  242. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  243. package/npm-shrinkwrap.json +9 -9
  244. package/package.json +4 -4
@@ -7,7 +7,7 @@ import * as fs from "node:fs";
7
7
  import * as os from "node:os";
8
8
  import * as path from "node:path";
9
9
  import { getProviders, } from "@earendil-works/pi-ai/compat";
10
- import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Loader, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
10
+ import { CombinedAutocompleteProvider, Container, fuzzyFilter, getCapabilities, hyperlink, Markdown, matchesKey, ProcessTerminal, Spacer, setKeybindings, Text, TruncatedText, TUI, visibleWidth, } from "@earendil-works/pi-tui";
11
11
  import chalk from "chalk";
12
12
  import { spawn, spawnSync } from "child_process";
13
13
  import { APP_NAME, APP_TITLE, CONFIG_DIR_NAME, expandTildePath, getAuthPath, getDebugLogPath, getDocsPath, getShareViewerUrl, VERSION, } from "../../config.js";
@@ -31,7 +31,7 @@ import { parseGitUrl } from "../../utils/git.js";
31
31
  import { getCwdRelativePath } from "../../utils/paths.js";
32
32
  import { getPiUserAgent } from "../../utils/pi-user-agent.js";
33
33
  import { killTrackedDetachedChildren } from "../../utils/shell.js";
34
- import { checkForNewPiVersion } from "../../utils/version-check.js";
34
+ import { checkForNewPiVersion, getReleaseChangelogUrl } from "../../utils/version-check.js";
35
35
  import { abortedErrorLabel } from "./aborted-error-label.js";
36
36
  import { ArminComponent } from "./components/armin.js";
37
37
  import { AssistantMessageComponent } from "./components/assistant-message.js";
@@ -39,7 +39,6 @@ import { BashExecutionComponent } from "./components/bash-execution.js";
39
39
  import { BorderedLoader } from "./components/bordered-loader.js";
40
40
  import { BranchSummaryMessageComponent } from "./components/branch-summary-message.js";
41
41
  import { CompactionSummaryMessageComponent } from "./components/compaction-summary-message.js";
42
- import { CountdownTimer } from "./components/countdown-timer.js";
43
42
  import { CustomEditor } from "./components/custom-editor.js";
44
43
  import { CustomMessageComponent } from "./components/custom-message.js";
45
44
  import { DaxnutsComponent } from "./components/daxnuts.js";
@@ -58,6 +57,7 @@ import { OAuthSelectorComponent } from "./components/oauth-selector.js";
58
57
  import { SessionSelectorComponent } from "./components/session-selector.js";
59
58
  import { SettingsSelectorComponent } from "./components/settings-selector.js";
60
59
  import { SkillInvocationMessageComponent } from "./components/skill-invocation-message.js";
60
+ import { BranchSummaryStatusIndicator, CompactionStatusIndicator, IdleStatus, RetryStatusIndicator, WorkingStatusIndicator, } from "./components/status-indicator.js";
61
61
  import { ToolExecutionComponent } from "./components/tool-execution.js";
62
62
  import { TreeSelectorComponent } from "./components/tree-selector.js";
63
63
  import { TrustSelectorComponent } from "./components/trust-selector.js";
@@ -197,12 +197,12 @@ export class InteractiveMode {
197
197
  this.autocompleteProviderWrappers = [];
198
198
  this.isInitialized = false;
199
199
  this.pendingUserInputs = [];
200
- this.loadingAnimation = undefined;
200
+ this.activeStatusIndicator = undefined;
201
+ this.idleStatus = new IdleStatus();
201
202
  this.workingMessage = undefined;
202
203
  this.workingVisible = true;
203
204
  this.workingIndicatorOptions = undefined;
204
205
  this.workingStartedAt = undefined;
205
- this.workingElapsedIntervalId = undefined;
206
206
  this.defaultWorkingMessage = "Working";
207
207
  this.defaultHiddenThinkingLabel = "Thinking...";
208
208
  this.hiddenThinkingLabel = this.defaultHiddenThinkingLabel;
@@ -230,6 +230,7 @@ export class InteractiveMode {
230
230
  this.toolOutputExpanded = false;
231
231
  // Thinking block visibility state
232
232
  this.hideThinkingBlock = false;
233
+ this.outputPad = 1;
233
234
  // Skill commands: command name -> skill file path
234
235
  this.skillCommands = new Map();
235
236
  this.signalCleanupHandlers = [];
@@ -239,12 +240,7 @@ export class InteractiveMode {
239
240
  this.bashComponent = undefined;
240
241
  // Track pending bash components (shown in pending area, moved to chat on submit)
241
242
  this.pendingBashComponents = [];
242
- // Auto-compaction state
243
- this.autoCompactionLoader = undefined;
244
243
  this.autoCompactionProgressText = "";
245
- // Auto-retry state
246
- this.retryLoader = undefined;
247
- this.retryCountdown = undefined;
248
244
  // Messages queued while compaction is running
249
245
  this.compactionQueuedMessages = [];
250
246
  // Shutdown state
@@ -305,6 +301,7 @@ export class InteractiveMode {
305
301
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
306
302
  // Load hide thinking block setting
307
303
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
304
+ this.outputPad = this.settingsManager.getOutputPad();
308
305
  // Register themes from resource loader and initialize
309
306
  setRegisteredThemes(this.session.resourceLoader.getThemes().themes);
310
307
  this.themeController = new InteractiveThemeController(this.ui, this.settingsManager, (message) => this.showError(message), () => this.updateEditorBorderColor());
@@ -1200,7 +1197,7 @@ export class InteractiveMode {
1200
1197
  commandContextActions: {
1201
1198
  waitForIdle: () => this.session.agent.waitForIdle(),
1202
1199
  newSession: async (options) => {
1203
- this.stopWorkingLoader();
1200
+ this.clearStatusIndicator();
1204
1201
  try {
1205
1202
  return await this.runtimeHost.newSession(options);
1206
1203
  }
@@ -1270,8 +1267,13 @@ export class InteractiveMode {
1270
1267
  this.footer.setAutoCompactEnabled(this.session.autoCompactionEnabled);
1271
1268
  this.footerDataProvider.setCwd(this.sessionManager.getCwd());
1272
1269
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
1270
+ this.outputPad = this.settingsManager.getOutputPad();
1273
1271
  this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
1274
- this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
1272
+ const clearOnShrink = this.settingsManager.getClearOnShrink();
1273
+ this.ui.setClearOnShrink(clearOnShrink);
1274
+ if (!clearOnShrink && !this.activeStatusIndicator) {
1275
+ this.statusContainer.clear();
1276
+ }
1275
1277
  const editorPaddingX = this.settingsManager.getEditorPaddingX();
1276
1278
  const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible();
1277
1279
  this.defaultEditor.setPaddingX(editorPaddingX);
@@ -1387,31 +1389,6 @@ export class InteractiveMode {
1387
1389
  this.footerDataProvider.setExtensionStatus(key, text);
1388
1390
  this.ui.requestRender();
1389
1391
  }
1390
- getWorkingLoaderMessage() {
1391
- return this.workingMessage ?? this.defaultWorkingMessage;
1392
- }
1393
- getWorkingElapsedSeconds() {
1394
- if (this.workingStartedAt === undefined) {
1395
- return 0;
1396
- }
1397
- return Math.max(0, Math.floor((Date.now() - this.workingStartedAt) / 1000));
1398
- }
1399
- refreshWorkingLoaderMessage() {
1400
- this.loadingAnimation?.setMessage(this.getWorkingLoaderMessage());
1401
- }
1402
- startWorkingElapsedTimer() {
1403
- this.stopWorkingElapsedTimer();
1404
- this.workingStartedAt = Date.now();
1405
- this.workingElapsedIntervalId = setInterval(() => {
1406
- this.refreshWorkingLoaderMessage();
1407
- }, DEFAULT_WORKING_STATUS_REFRESH_INTERVAL_MS);
1408
- }
1409
- stopWorkingElapsedTimer() {
1410
- if (this.workingElapsedIntervalId) {
1411
- clearInterval(this.workingElapsedIntervalId);
1412
- this.workingElapsedIntervalId = undefined;
1413
- }
1414
- }
1415
1392
  startToolHookStatusTimer() {
1416
1393
  if (this.hookStatusIntervalId) {
1417
1394
  return;
@@ -1522,6 +1499,23 @@ export class InteractiveMode {
1522
1499
  this.hookStatusContainer.clear();
1523
1500
  this.stopToolHookStatusTimer();
1524
1501
  }
1502
+ getWorkingElapsedSeconds() {
1503
+ if (this.workingStartedAt === undefined) {
1504
+ return 0;
1505
+ }
1506
+ return Math.max(0, Math.floor((Date.now() - this.workingStartedAt) / 1000));
1507
+ }
1508
+ getWorkingLoaderMessage() {
1509
+ return this.workingMessage ?? this.defaultWorkingMessage;
1510
+ }
1511
+ refreshWorkingLoaderMessage() {
1512
+ if (this.activeStatusIndicator?.kind === "working") {
1513
+ this.activeStatusIndicator.setMessage(this.getWorkingLoaderMessage());
1514
+ return;
1515
+ }
1516
+ const legacyLoader = this.loadingAnimation;
1517
+ legacyLoader?.setMessage(this.getWorkingLoaderMessage());
1518
+ }
1525
1519
  getWorkingIndicatorOptions() {
1526
1520
  return (this.workingIndicatorOptions ?? {
1527
1521
  frames: theme.getColorMode() === "truecolor" ? ["•"] : [theme.fg("accent", "•"), theme.fg("muted", "◦")],
@@ -1539,36 +1533,53 @@ export class InteractiveMode {
1539
1533
  messageIntervalMs: DEFAULT_WORKING_STATUS_MESSAGE_ANIMATION_INTERVAL_MS,
1540
1534
  });
1541
1535
  }
1542
- createWorkingLoader() {
1543
- return new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), this.getWorkingLoaderMessage(), this.getWorkingIndicatorOptions());
1536
+ showStatusIndicator(indicator) {
1537
+ if (indicator.kind === "working") {
1538
+ this.workingStartedAt = Date.now();
1539
+ }
1540
+ this.activeStatusIndicator?.dispose();
1541
+ this.activeStatusIndicator = indicator;
1542
+ this.statusContainer.clear();
1543
+ this.statusContainer.addChild(indicator);
1544
1544
  }
1545
- stopWorkingLoader() {
1546
- this.stopWorkingElapsedTimer();
1547
- this.workingStartedAt = undefined;
1548
- if (this.loadingAnimation) {
1549
- this.loadingAnimation.stop();
1550
- this.loadingAnimation = undefined;
1545
+ updateWorkingIndicatorMessage() {
1546
+ if (this.activeStatusIndicator?.kind === "working") {
1547
+ this.activeStatusIndicator.setMessage(this.workingMessage ?? this.defaultWorkingMessage);
1548
+ }
1549
+ }
1550
+ clearStatusIndicator(kind) {
1551
+ if (kind && this.activeStatusIndicator?.kind !== kind) {
1552
+ return;
1553
+ }
1554
+ const hadActiveStatusIndicator = this.activeStatusIndicator !== undefined;
1555
+ const isClearingWorking = this.activeStatusIndicator?.kind === "working";
1556
+ this.activeStatusIndicator?.dispose();
1557
+ this.activeStatusIndicator = undefined;
1558
+ if (isClearingWorking) {
1559
+ this.workingStartedAt = undefined;
1551
1560
  }
1552
1561
  this.statusContainer.clear();
1562
+ if (hadActiveStatusIndicator && this.ui.getClearOnShrink()) {
1563
+ this.statusContainer.addChild(this.idleStatus);
1564
+ }
1553
1565
  }
1554
1566
  setWorkingVisible(visible) {
1555
1567
  this.workingVisible = visible;
1556
1568
  if (!visible) {
1557
- this.stopWorkingLoader();
1569
+ this.clearStatusIndicator("working");
1558
1570
  this.ui.requestRender();
1559
1571
  return;
1560
1572
  }
1561
- if (this.session.isStreaming && !this.loadingAnimation) {
1562
- this.statusContainer.clear();
1563
- this.startWorkingElapsedTimer();
1564
- this.loadingAnimation = this.createWorkingLoader();
1565
- this.statusContainer.addChild(this.loadingAnimation);
1573
+ if (this.session.isStreaming && this.activeStatusIndicator?.kind !== "working") {
1574
+ this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.getWorkingIndicatorOptions()));
1566
1575
  }
1567
1576
  this.ui.requestRender();
1568
1577
  }
1569
1578
  setWorkingIndicator(options) {
1570
1579
  this.workingIndicatorOptions = options;
1571
- this.loadingAnimation?.setIndicator(this.getWorkingIndicatorOptions());
1580
+ if (this.activeStatusIndicator?.kind === "working") {
1581
+ this.activeStatusIndicator.setIndicator(this.getWorkingIndicatorOptions());
1582
+ }
1572
1583
  this.ui.requestRender();
1573
1584
  }
1574
1585
  setHiddenThinkingLabel(label) {
@@ -1660,7 +1671,7 @@ export class InteractiveMode {
1660
1671
  this.workingMessage = undefined;
1661
1672
  this.workingVisible = true;
1662
1673
  this.setWorkingIndicator();
1663
- this.refreshWorkingLoaderMessage();
1674
+ this.updateWorkingIndicatorMessage();
1664
1675
  this.setHiddenThinkingLabel();
1665
1676
  this.clearToolHookStatuses();
1666
1677
  }
@@ -1800,7 +1811,7 @@ export class InteractiveMode {
1800
1811
  setStatus: (key, text) => this.setExtensionStatus(key, text),
1801
1812
  setWorkingMessage: (message) => {
1802
1813
  this.workingMessage = message;
1803
- this.refreshWorkingLoaderMessage();
1814
+ this.updateWorkingIndicatorMessage();
1804
1815
  },
1805
1816
  setWorkingVisible: (visible) => this.setWorkingVisible(visible),
1806
1817
  setWorkingIndicator: (options) => this.setWorkingIndicator(options),
@@ -2443,19 +2454,11 @@ export class InteractiveMode {
2443
2454
  this.defaultEditor.onEscape = this.retryEscapeHandler;
2444
2455
  this.retryEscapeHandler = undefined;
2445
2456
  }
2446
- if (this.retryCountdown) {
2447
- this.retryCountdown.dispose();
2448
- this.retryCountdown = undefined;
2449
- }
2450
- if (this.retryLoader) {
2451
- this.retryLoader.stop();
2452
- this.retryLoader = undefined;
2453
- }
2454
- this.stopWorkingLoader();
2455
2457
  if (this.workingVisible) {
2456
- this.startWorkingElapsedTimer();
2457
- this.loadingAnimation = this.createWorkingLoader();
2458
- this.statusContainer.addChild(this.loadingAnimation);
2458
+ this.showStatusIndicator(new WorkingStatusIndicator(this.ui, this.workingMessage ?? this.defaultWorkingMessage, this.getWorkingIndicatorOptions()));
2459
+ }
2460
+ else {
2461
+ this.clearStatusIndicator();
2459
2462
  }
2460
2463
  this.ui.requestRender();
2461
2464
  break;
@@ -2486,7 +2489,7 @@ export class InteractiveMode {
2486
2489
  this.ui.requestRender();
2487
2490
  }
2488
2491
  else if (event.message.role === "assistant") {
2489
- this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
2492
+ this.streamingComponent = new AssistantMessageComponent(undefined, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2490
2493
  this.streamingComponent.setExpanded(this.toolOutputExpanded);
2491
2494
  this.streamingMessage = event.message;
2492
2495
  this.chatContainer.addChild(this.streamingComponent);
@@ -2596,7 +2599,7 @@ export class InteractiveMode {
2596
2599
  if (this.settingsManager.getShowTerminalProgress()) {
2597
2600
  this.ui.terminal.setProgress(false);
2598
2601
  }
2599
- this.stopWorkingLoader();
2602
+ this.clearStatusIndicator("working");
2600
2603
  this.clearActiveToolExecutionStatus();
2601
2604
  this.clearToolHookStatuses();
2602
2605
  if (this.streamingComponent) {
@@ -2617,23 +2620,17 @@ export class InteractiveMode {
2617
2620
  this.defaultEditor.onEscape = () => {
2618
2621
  this.session.abortCompaction();
2619
2622
  };
2623
+ const indicator = new CompactionStatusIndicator(this.ui, event.reason);
2624
+ this.activeStatusIndicator?.dispose();
2625
+ this.activeStatusIndicator = indicator;
2620
2626
  this.statusContainer.clear();
2621
- const cancelHint = `(${keyText("app.interrupt")} to cancel)`;
2622
- const label = event.reason === "threshold"
2623
- ? `Auto-compacting... ${cancelHint}`
2624
- : event.reason === "overflow"
2625
- ? `Context overflow detected, compacting... ${cancelHint}`
2626
- : event.reason === "pre_prompt"
2627
- ? `Compacting before next prompt... ${cancelHint}`
2628
- : `Compacting context... ${cancelHint}`;
2629
- this.autoCompactionLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label);
2630
- this.statusContainer.addChild(this.autoCompactionLoader);
2627
+ this.statusContainer.addChild(indicator);
2631
2628
  this.autoCompactionProgressText = "";
2632
2629
  this.ui.requestRender();
2633
2630
  break;
2634
2631
  }
2635
2632
  case "compaction_progress": {
2636
- if (!this.autoCompactionLoader)
2633
+ if (this.activeStatusIndicator?.kind !== "compaction")
2637
2634
  break;
2638
2635
  const nextText = event.text !== undefined ? event.text : `${this.autoCompactionProgressText}${event.delta ?? ""}`;
2639
2636
  if (!nextText)
@@ -2641,7 +2638,7 @@ export class InteractiveMode {
2641
2638
  this.autoCompactionProgressText = nextText;
2642
2639
  const preview = nextText.length > 4_000 ? `...${nextText.slice(nextText.length - 4_000)}` : nextText;
2643
2640
  this.statusContainer.clear();
2644
- this.statusContainer.addChild(this.autoCompactionLoader);
2641
+ this.statusContainer.addChild(this.activeStatusIndicator);
2645
2642
  this.statusContainer.addChild(new Spacer(1));
2646
2643
  this.statusContainer.addChild(new Text(theme.fg("muted", preview), 1, 0));
2647
2644
  this.ui.requestRender();
@@ -2655,12 +2652,8 @@ export class InteractiveMode {
2655
2652
  this.defaultEditor.onEscape = this.autoCompactionEscapeHandler;
2656
2653
  this.autoCompactionEscapeHandler = undefined;
2657
2654
  }
2658
- if (this.autoCompactionLoader) {
2659
- this.autoCompactionLoader.stop();
2660
- this.autoCompactionLoader = undefined;
2661
- this.autoCompactionProgressText = "";
2662
- this.statusContainer.clear();
2663
- }
2655
+ this.clearStatusIndicator("compaction");
2656
+ this.autoCompactionProgressText = "";
2664
2657
  if (event.aborted) {
2665
2658
  if (event.reason === "manual") {
2666
2659
  this.showError("Compaction cancelled");
@@ -2694,17 +2687,7 @@ export class InteractiveMode {
2694
2687
  // no separate retry-only handler is installed (the prior one only called
2695
2688
  // session.abortRetry() and left queued steering messages stranded).
2696
2689
  this.retryEscapeHandler = undefined;
2697
- // Show retry indicator
2698
- this.statusContainer.clear();
2699
- this.retryCountdown?.dispose();
2700
- const retryMessage = (seconds) => `Retrying (${event.attempt}/${event.maxAttempts}) in ${seconds}s... (${keyText("app.interrupt")} to cancel)`;
2701
- this.retryLoader = new Loader(this.ui, (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), retryMessage(Math.ceil(event.delayMs / 1000)));
2702
- this.retryCountdown = new CountdownTimer(event.delayMs, this.ui, (seconds) => {
2703
- this.retryLoader?.setMessage(retryMessage(seconds));
2704
- }, () => {
2705
- this.retryCountdown = undefined;
2706
- });
2707
- this.statusContainer.addChild(this.retryLoader);
2690
+ this.showStatusIndicator(new RetryStatusIndicator(this.ui, event.attempt, event.maxAttempts, event.delayMs));
2708
2691
  this.ui.requestRender();
2709
2692
  break;
2710
2693
  }
@@ -2714,16 +2697,7 @@ export class InteractiveMode {
2714
2697
  this.defaultEditor.onEscape = this.retryEscapeHandler;
2715
2698
  this.retryEscapeHandler = undefined;
2716
2699
  }
2717
- if (this.retryCountdown) {
2718
- this.retryCountdown.dispose();
2719
- this.retryCountdown = undefined;
2720
- }
2721
- // Stop loader
2722
- if (this.retryLoader) {
2723
- this.retryLoader.stop();
2724
- this.retryLoader = undefined;
2725
- this.statusContainer.clear();
2726
- }
2700
+ this.clearStatusIndicator("retry");
2727
2701
  // Show error only on final failure (success shows normal response)
2728
2702
  if (!event.success) {
2729
2703
  this.showError(`Retry failed after ${event.attempt} attempts: ${event.finalError || "Unknown error"}`);
@@ -2814,12 +2788,12 @@ export class InteractiveMode {
2814
2788
  // Render user message separately if present
2815
2789
  if (skillBlock.userMessage) {
2816
2790
  this.chatContainer.addChild(new Spacer(1));
2817
- const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings());
2791
+ const userComponent = new UserMessageComponent(skillBlock.userMessage, this.getMarkdownThemeWithSettings(), this.outputPad);
2818
2792
  this.chatContainer.addChild(userComponent);
2819
2793
  }
2820
2794
  }
2821
2795
  else {
2822
- const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings());
2796
+ const userComponent = new UserMessageComponent(textContent, this.getMarkdownThemeWithSettings(), this.outputPad);
2823
2797
  this.chatContainer.addChild(userComponent);
2824
2798
  }
2825
2799
  if (options?.populateHistory) {
@@ -2829,7 +2803,7 @@ export class InteractiveMode {
2829
2803
  break;
2830
2804
  }
2831
2805
  case "assistant": {
2832
- const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel);
2806
+ const assistantComponent = new AssistantMessageComponent(message, this.hideThinkingBlock, this.getMarkdownThemeWithSettings(), this.hiddenThinkingLabel, this.outputPad);
2833
2807
  assistantComponent.setExpanded(this.toolOutputExpanded);
2834
2808
  this.chatContainer.addChild(assistantComponent);
2835
2809
  break;
@@ -3304,7 +3278,7 @@ export class InteractiveMode {
3304
3278
  showNewVersionNotification(newVersion) {
3305
3279
  const action = theme.fg("accent", `${APP_NAME} update`);
3306
3280
  const updateInstruction = theme.fg("muted", `New version ${newVersion} is available. Run `) + action;
3307
- const changelogUrl = "https://github.com/earendil-works/pi-mono/blob/main/packages/coding-agent/CHANGELOG.md";
3281
+ const changelogUrl = getReleaseChangelogUrl(newVersion);
3308
3282
  const changelogLink = getCapabilities().hyperlinks
3309
3283
  ? hyperlink(theme.fg("accent", changelogUrl), changelogUrl)
3310
3284
  : theme.fg("accent", changelogUrl);
@@ -3557,6 +3531,7 @@ export class InteractiveMode {
3557
3531
  showHardwareCursor: this.settingsManager.getShowHardwareCursor(),
3558
3532
  defaultProjectTrust: this.settingsManager.getDefaultProjectTrust(),
3559
3533
  editorPaddingX: this.settingsManager.getEditorPaddingX(),
3534
+ outputPad: this.settingsManager.getOutputPad(),
3560
3535
  autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(),
3561
3536
  quietStartup: this.settingsManager.getQuietStartup(),
3562
3537
  clearOnShrink: this.settingsManager.getClearOnShrink(),
@@ -3658,6 +3633,23 @@ export class InteractiveMode {
3658
3633
  this.editor.setPaddingX(padding);
3659
3634
  }
3660
3635
  },
3636
+ onOutputPadChange: (padding) => {
3637
+ this.settingsManager.setOutputPad(padding);
3638
+ this.outputPad = padding;
3639
+ if (this.streamingComponent || this.session.isStreaming) {
3640
+ for (const child of this.chatContainer.children) {
3641
+ if (child instanceof AssistantMessageComponent || child instanceof UserMessageComponent) {
3642
+ child.setOutputPad(padding);
3643
+ }
3644
+ }
3645
+ if (this.streamingComponent) {
3646
+ this.streamingComponent.setOutputPad(padding);
3647
+ }
3648
+ this.ui.requestRender();
3649
+ return;
3650
+ }
3651
+ this.rebuildChatFromMessages();
3652
+ },
3661
3653
  onAutocompleteMaxVisibleChange: (maxVisible) => {
3662
3654
  this.settingsManager.setAutocompleteMaxVisible(maxVisible);
3663
3655
  this.defaultEditor.setAutocompleteMaxVisible(maxVisible);
@@ -3668,6 +3660,9 @@ export class InteractiveMode {
3668
3660
  onClearOnShrinkChange: (enabled) => {
3669
3661
  this.settingsManager.setClearOnShrink(enabled);
3670
3662
  this.ui.setClearOnShrink(enabled);
3663
+ if (!enabled && !this.activeStatusIndicator) {
3664
+ this.statusContainer.clear();
3665
+ }
3671
3666
  },
3672
3667
  onShowTerminalProgressChange: (enabled) => {
3673
3668
  this.settingsManager.setShowTerminalProgress(enabled);
@@ -3999,16 +3994,16 @@ export class InteractiveMode {
3999
3994
  break;
4000
3995
  }
4001
3996
  }
4002
- // Set up escape handler and loader if summarizing
4003
- let summaryLoader;
3997
+ // Set up escape handler and status indicator if summarizing
3998
+ let showingSummaryIndicator = false;
4004
3999
  const originalOnEscape = this.defaultEditor.onEscape;
4005
4000
  if (wantsSummary) {
4006
4001
  this.defaultEditor.onEscape = () => {
4007
4002
  this.session.abortBranchSummary();
4008
4003
  };
4009
4004
  this.chatContainer.addChild(new Spacer(1));
4010
- summaryLoader = new Loader(this.ui, (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Summarizing branch... (${keyText("app.interrupt")} to cancel)`);
4011
- this.statusContainer.addChild(summaryLoader);
4005
+ this.showStatusIndicator(new BranchSummaryStatusIndicator(this.ui));
4006
+ showingSummaryIndicator = true;
4012
4007
  this.ui.requestRender();
4013
4008
  }
4014
4009
  try {
@@ -4039,9 +4034,8 @@ export class InteractiveMode {
4039
4034
  this.showError(error instanceof Error ? error.message : String(error));
4040
4035
  }
4041
4036
  finally {
4042
- if (summaryLoader) {
4043
- summaryLoader.stop();
4044
- this.statusContainer.clear();
4037
+ if (showingSummaryIndicator) {
4038
+ this.clearStatusIndicator("branchSummary");
4045
4039
  }
4046
4040
  this.defaultEditor.onEscape = originalOnEscape;
4047
4041
  }
@@ -4082,7 +4076,7 @@ export class InteractiveMode {
4082
4076
  });
4083
4077
  }
4084
4078
  async handleResumeSession(sessionPath, options) {
4085
- this.stopWorkingLoader();
4079
+ this.clearStatusIndicator();
4086
4080
  try {
4087
4081
  const result = await this.runtimeHost.switchSession(sessionPath, {
4088
4082
  withSession: options?.withSession,
@@ -4477,6 +4471,7 @@ export class InteractiveMode {
4477
4471
  return;
4478
4472
  }
4479
4473
  this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock();
4474
+ this.outputPad = this.settingsManager.getOutputPad();
4480
4475
  this.rebuildChatFromMessages();
4481
4476
  chatRestoredBeforeSessionStart = true;
4482
4477
  };
@@ -4500,7 +4495,11 @@ export class InteractiveMode {
4500
4495
  this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible);
4501
4496
  }
4502
4497
  this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor());
4503
- this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink());
4498
+ const clearOnShrink = this.settingsManager.getClearOnShrink();
4499
+ this.ui.setClearOnShrink(clearOnShrink);
4500
+ if (!clearOnShrink && !this.activeStatusIndicator) {
4501
+ this.statusContainer.clear();
4502
+ }
4504
4503
  this.setupAutocompleteProvider();
4505
4504
  const runner = this.session.extensionRunner;
4506
4505
  this.setupExtensionShortcuts(runner);
@@ -4579,7 +4578,7 @@ export class InteractiveMode {
4579
4578
  return;
4580
4579
  }
4581
4580
  try {
4582
- this.stopWorkingLoader();
4581
+ this.clearStatusIndicator();
4583
4582
  const result = await this.runtimeHost.importFromJsonl(inputPath);
4584
4583
  if (result.cancelled) {
4585
4584
  this.showStatus("Import cancelled");
@@ -4882,7 +4881,7 @@ export class InteractiveMode {
4882
4881
  this.ui.requestRender();
4883
4882
  }
4884
4883
  async handleClearCommand() {
4885
- this.stopWorkingLoader();
4884
+ this.clearStatusIndicator();
4886
4885
  try {
4887
4886
  const result = await this.runtimeHost.newSession();
4888
4887
  if (result.cancelled) {
@@ -5015,8 +5014,7 @@ export class InteractiveMode {
5015
5014
  this.showWarning("Nothing to compact (no messages yet)");
5016
5015
  return;
5017
5016
  }
5018
- this.stopWorkingLoader();
5019
- this.statusContainer.clear();
5017
+ this.clearStatusIndicator();
5020
5018
  try {
5021
5019
  await this.session.compact(customInstructions);
5022
5020
  }
@@ -5028,7 +5026,7 @@ export class InteractiveMode {
5028
5026
  if (this.settingsManager.getShowTerminalProgress()) {
5029
5027
  this.ui.terminal.setProgress(false);
5030
5028
  }
5031
- this.stopWorkingLoader();
5029
+ this.clearStatusIndicator();
5032
5030
  this.clearPendingTools();
5033
5031
  this.clearActiveToolExecutionStatus();
5034
5032
  this.clearToolHookStatuses();