@oh-my-pi/pi-coding-agent 13.9.13 → 13.9.15

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [13.9.15] - 2026-03-10
6
+ ### Added
7
+
8
+ - Added `ensureLoadingAnimation()` method to manage loading animation lifecycle and prevent duplicate spinners
9
+
10
+ ### Changed
11
+
12
+ - Refactored loading animation initialization to use centralized `ensureLoadingAnimation()` method in event and input controllers
13
+ - Updated `showError()` to properly clean up loading animation state when errors occur
14
+
5
15
  ## [13.9.12] - 2026-03-09
6
16
  ### Added
7
17
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@oh-my-pi/pi-coding-agent",
4
- "version": "13.9.13",
4
+ "version": "13.9.15",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/can1357/oh-my-pi",
7
7
  "author": "Can Boluk",
@@ -41,12 +41,12 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@mozilla/readability": "^0.6",
44
- "@oh-my-pi/omp-stats": "13.9.13",
45
- "@oh-my-pi/pi-agent-core": "13.9.13",
46
- "@oh-my-pi/pi-ai": "13.9.13",
47
- "@oh-my-pi/pi-natives": "13.9.13",
48
- "@oh-my-pi/pi-tui": "13.9.13",
49
- "@oh-my-pi/pi-utils": "13.9.13",
44
+ "@oh-my-pi/omp-stats": "13.9.15",
45
+ "@oh-my-pi/pi-agent-core": "13.9.15",
46
+ "@oh-my-pi/pi-ai": "13.9.15",
47
+ "@oh-my-pi/pi-natives": "13.9.15",
48
+ "@oh-my-pi/pi-tui": "13.9.15",
49
+ "@oh-my-pi/pi-utils": "13.9.15",
50
50
  "@sinclair/typebox": "^0.34",
51
51
  "@xterm/headless": "^6.0",
52
52
  "ajv": "^8.18",
@@ -107,19 +107,7 @@ export class EventController {
107
107
  this.ctx.retryLoader = undefined;
108
108
  this.ctx.statusContainer.clear();
109
109
  }
110
- if (this.ctx.loadingAnimation) {
111
- this.ctx.loadingAnimation.stop();
112
- }
113
- this.ctx.statusContainer.clear();
114
- this.ctx.loadingAnimation = new Loader(
115
- this.ctx.ui,
116
- spinner => theme.fg("accent", spinner),
117
- text => theme.fg("muted", text),
118
- `Working… (esc to interrupt)`,
119
- getSymbolTheme().spinnerFrames,
120
- );
121
- this.ctx.statusContainer.addChild(this.ctx.loadingAnimation);
122
- this.ctx.applyPendingWorkingMessage();
110
+ this.ctx.ensureLoadingAnimation();
123
111
  this.ctx.ui.requestRender();
124
112
  break;
125
113
 
@@ -339,6 +339,7 @@ export class InputController {
339
339
  };
340
340
  this.ctx.addMessageToChat(optimisticMessage);
341
341
  this.ctx.editor.setText("");
342
+ this.ctx.ensureLoadingAnimation();
342
343
  this.ctx.ui.requestRender();
343
344
 
344
345
  this.ctx.onInputCallback({ text, images });
@@ -5,8 +5,8 @@
5
5
  import * as path from "node:path";
6
6
  import { type Agent, type AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
7
7
  import type { AssistantMessage, ImageContent, Message, Model, UsageReport } from "@oh-my-pi/pi-ai";
8
- import type { Component, Loader, SlashCommand } from "@oh-my-pi/pi-tui";
9
- import { Container, Markdown, ProcessTerminal, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
8
+ import type { Component, SlashCommand } from "@oh-my-pi/pi-tui";
9
+ import { Container, Loader, Markdown, ProcessTerminal, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
10
10
  import { APP_NAME, getProjectDir, hsvToRgb, isEnoent, logger, postmortem } from "@oh-my-pi/pi-utils";
11
11
  import chalk from "chalk";
12
12
  import { KeybindingsManager } from "../config/keybindings";
@@ -46,7 +46,14 @@ import { SSHCommandController } from "./controllers/ssh-command-controller";
46
46
  import { OAuthManualInputManager } from "./oauth-manual-input";
47
47
  import { setMermaidRenderCallback } from "./theme/mermaid-cache";
48
48
  import type { Theme } from "./theme/theme";
49
- import { getEditorTheme, getMarkdownTheme, onTerminalAppearanceChange, onThemeChange, theme } from "./theme/theme";
49
+ import {
50
+ getEditorTheme,
51
+ getMarkdownTheme,
52
+ getSymbolTheme,
53
+ onTerminalAppearanceChange,
54
+ onThemeChange,
55
+ theme,
56
+ } from "./theme/theme";
50
57
  import type { CompactionQueuedMessage, InteractiveModeContext, TodoItem, TodoPhase } from "./types";
51
58
  import { UiHelpers } from "./utils/ui-helpers";
52
59
 
@@ -849,6 +856,12 @@ export class InteractiveMode implements InteractiveModeContext {
849
856
 
850
857
  showError(message: string): void {
851
858
  this.optimisticUserMessageSignature = undefined;
859
+ this.#pendingWorkingMessage = undefined;
860
+ if (this.loadingAnimation) {
861
+ this.loadingAnimation.stop();
862
+ this.loadingAnimation = undefined;
863
+ this.statusContainer.clear();
864
+ }
852
865
  this.#uiHelpers.showError(message);
853
866
  }
854
867
 
@@ -856,6 +869,22 @@ export class InteractiveMode implements InteractiveModeContext {
856
869
  this.#uiHelpers.showWarning(message);
857
870
  }
858
871
 
872
+ ensureLoadingAnimation(): void {
873
+ if (!this.loadingAnimation) {
874
+ this.statusContainer.clear();
875
+ this.loadingAnimation = new Loader(
876
+ this.ui,
877
+ spinner => theme.fg("accent", spinner),
878
+ text => theme.fg("muted", text),
879
+ this.#defaultWorkingMessage,
880
+ getSymbolTheme().spinnerFrames,
881
+ );
882
+ this.statusContainer.addChild(this.loadingAnimation);
883
+ }
884
+
885
+ this.applyPendingWorkingMessage();
886
+ }
887
+
859
888
  setWorkingMessage(message?: string): void {
860
889
  if (message === undefined) {
861
890
  this.#pendingWorkingMessage = undefined;
@@ -128,6 +128,7 @@ export interface InteractiveModeContext {
128
128
  flushPendingModelSwitch(): Promise<void>;
129
129
  setWorkingMessage(message?: string): void;
130
130
  applyPendingWorkingMessage(): void;
131
+ ensureLoadingAnimation(): void;
131
132
  isKnownSlashCommand(text: string): boolean;
132
133
  addMessageToChat(message: AgentMessage, options?: { populateHistory?: boolean }): void;
133
134
  renderSessionContext(
@@ -1,9 +1,9 @@
1
1
  ---
2
2
  name: explore
3
3
  description: Fast read-only codebase scout returning compressed context for handoff
4
- tools: read, grep, find, bash, lsp, fetch, web_search, ast_grep
4
+ tools: read, grep, find, fetch, web_search
5
5
  model: pi/smol
6
- thinking-level: minimal
6
+ thinking-level: off
7
7
  output:
8
8
  properties:
9
9
  summary:
@@ -227,10 +227,10 @@ Remote filesystems: `~/.omp/remote/<hostname>/`. Windows paths need colons: `C:/
227
227
  ### Search before you read
228
228
 
229
229
  Don't open a file hoping. Hope is not a strategy.
230
- {{#has tools "task"}}- `task` to explore rapidly{{/has}}
231
230
  {{#has tools "grep"}}- `grep` to locate target{{/has}}
232
231
  {{#has tools "find"}}- `find` to map it{{/has}}
233
232
  {{#has tools "read"}}- `read` with offset/limit, not whole file{{/has}}
233
+ {{#has tools "task"}}- `task` to gather context if needed via explore agent{{/has}}
234
234
  {{/ifAny}}
235
235
 
236
236
  {{#if (includes tools "inspect_image")}}