@oh-my-pi/pi-coding-agent 6.8.4 → 6.9.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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [6.9.0] - 2026-01-21
6
+ ### Removed
7
+
8
+ - Removed Git tool and all related functionality
9
+ - Removed voice control and TTS features
10
+ - Removed worktree management system
11
+ - Removed bundled wt custom command
12
+ - Removed voice-related settings and configuration options
13
+ - Removed @oh-my-pi/pi-git-tool dependency
14
+
15
+ ## [6.8.5] - 2026-01-21
16
+ ### Breaking Changes
17
+
18
+ - Changed timeout parameter from seconds to milliseconds in Python tool
19
+ - Updated PythonExecutorOptions interface to use timeoutMs instead of timeout
20
+
21
+ ### Changed
22
+
23
+ - Updated default timeout to 30000ms (30 seconds) for Python tool
24
+ - Improved streaming output handling and buffer management
25
+
5
26
  ## [6.8.4] - 2026-01-21
6
27
  ### Changed
7
28
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oh-my-pi/pi-coding-agent",
3
- "version": "6.8.4",
3
+ "version": "6.9.0",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "ompConfig": {
@@ -40,11 +40,10 @@
40
40
  "prepublishOnly": "bun run generate-template && bun run clean && bun run build"
41
41
  },
42
42
  "dependencies": {
43
- "@oh-my-pi/pi-agent-core": "6.8.4",
44
- "@oh-my-pi/pi-ai": "6.8.4",
45
- "@oh-my-pi/pi-git-tool": "6.8.4",
46
- "@oh-my-pi/pi-tui": "6.8.4",
47
- "@oh-my-pi/pi-utils": "6.8.4",
43
+ "@oh-my-pi/pi-agent-core": "6.9.0",
44
+ "@oh-my-pi/pi-ai": "6.9.0",
45
+ "@oh-my-pi/pi-tui": "6.9.0",
46
+ "@oh-my-pi/pi-utils": "6.9.0",
48
47
  "@openai/agents": "^0.3.7",
49
48
  "@sinclair/typebox": "^0.34.46",
50
49
  "ajv": "^8.17.1",
@@ -14,9 +14,9 @@ export interface PythonExecutorOptions {
14
14
  /** Working directory for command execution */
15
15
  cwd?: string;
16
16
  /** Timeout in milliseconds */
17
- timeout?: number;
17
+ timeoutMs?: number;
18
18
  /** Callback for streaming output chunks (already sanitized) */
19
- onChunk?: (chunk: string) => void;
19
+ onChunk?: (chunk: string) => Promise<void> | void;
20
20
  /** AbortSignal for cancellation */
21
21
  signal?: AbortSignal;
22
22
  /** Session identifier for kernel reuse */
@@ -216,17 +216,13 @@ async function executeWithKernel(
216
216
  try {
217
217
  const result = await kernel.execute(code, {
218
218
  signal: options?.signal,
219
- timeoutMs: options?.timeout,
220
- onChunk: (text) => {
221
- sink.push(text);
222
- },
223
- onDisplay: (output) => {
224
- displayOutputs.push(output);
225
- },
219
+ timeoutMs: options?.timeoutMs,
220
+ onChunk: (text) => sink.push(text),
221
+ onDisplay: (output) => void displayOutputs.push(output),
226
222
  });
227
223
 
228
224
  if (result.cancelled) {
229
- const secs = options?.timeout ? Math.round(options.timeout / 1000) : undefined;
225
+ const secs = options?.timeoutMs ? Math.round(options.timeoutMs / 1000) : undefined;
230
226
  const annotation =
231
227
  result.timedOut && secs !== undefined ? `Command timed out after ${secs} seconds` : undefined;
232
228
  return {
package/src/core/sdk.ts CHANGED
@@ -86,7 +86,6 @@ import {
86
86
  createTools,
87
87
  EditTool,
88
88
  FindTool,
89
- GitTool,
90
89
  GrepTool,
91
90
  getWebSearchTools,
92
91
  LsTool,
@@ -218,7 +217,6 @@ export {
218
217
  createTools,
219
218
  EditTool,
220
219
  FindTool,
221
- GitTool,
222
220
  GrepTool,
223
221
  loadSshTool,
224
222
  LsTool,
@@ -98,10 +98,6 @@ export interface BashInterceptorSettings {
98
98
  patterns?: BashInterceptorRule[]; // default: built-in rules
99
99
  }
100
100
 
101
- export interface GitSettings {
102
- enabled?: boolean; // default: false (structured git tool; use bash for git commands when disabled)
103
- }
104
-
105
101
  export interface MCPSettings {
106
102
  enableProjectConfig?: boolean; // default: true (load .mcp.json from project root)
107
103
  }
@@ -145,15 +141,6 @@ export interface TodoCompletionSettings {
145
141
  maxReminders?: number; // default: 3 - maximum reminders before giving up
146
142
  }
147
143
 
148
- export interface VoiceSettings {
149
- enabled?: boolean; // default: false
150
- transcriptionModel?: string; // default: "whisper-1"
151
- transcriptionLanguage?: string; // optional language hint (e.g., "en")
152
- ttsModel?: string; // default: "gpt-4o-mini-tts"
153
- ttsVoice?: string; // default: "alloy"
154
- ttsFormat?: "wav" | "mp3" | "opus" | "aac" | "flac"; // default: "wav"
155
- }
156
-
157
144
  export type StatusLineSegmentId =
158
145
  | "pi"
159
146
  | "model"
@@ -224,14 +211,12 @@ export interface Settings {
224
211
  enabledModels?: string[]; // Model patterns for cycling (same format as --models CLI flag)
225
212
  exa?: ExaSettings;
226
213
  bashInterceptor?: BashInterceptorSettings;
227
- git?: GitSettings;
228
214
  mcp?: MCPSettings;
229
215
  lsp?: LspSettings;
230
216
  python?: PythonSettings;
231
217
  edit?: EditSettings;
232
218
  ttsr?: TtsrSettings;
233
219
  todoCompletion?: TodoCompletionSettings;
234
- voice?: VoiceSettings;
235
220
  providers?: ProviderSettings;
236
221
  disabledProviders?: string[]; // Discovery provider IDs that are disabled
237
222
  disabledExtensions?: string[]; // Individual extension IDs that are disabled (e.g., "skill:commit")
@@ -252,12 +237,6 @@ export const DEFAULT_BASH_INTERCEPTOR_RULES: BashInterceptorRule[] = [
252
237
  tool: "grep",
253
238
  message: "Use the `grep` tool instead of grep/rg. It respects .gitignore and provides structured output.",
254
239
  },
255
- {
256
- pattern: "^\\s*git(\\s+|$)",
257
- tool: "git",
258
- message:
259
- "Use the `git` tool instead of running git in bash. It provides structured output and safety confirmations.",
260
- },
261
240
  {
262
241
  pattern: "^\\s*(find|fd|locate)\\s+.*(-name|-iname|-type|--type|-glob)",
263
242
  tool: "find",
@@ -319,19 +298,11 @@ const DEFAULT_SETTINGS: Settings = {
319
298
  enableWebsets: false,
320
299
  },
321
300
  bashInterceptor: DEFAULT_BASH_INTERCEPTOR_SETTINGS,
322
- git: { enabled: false },
323
301
  mcp: { enableProjectConfig: true },
324
302
  lsp: { formatOnWrite: false, diagnosticsOnWrite: true, diagnosticsOnEdit: false },
325
303
  python: { toolMode: "both", kernelMode: "session", sharedGateway: true },
326
304
  edit: { fuzzyMatch: true, fuzzyThreshold: 0.95, streamingAbort: false },
327
305
  ttsr: { enabled: true, contextMode: "discard", repeatMode: "once", repeatGap: 10 },
328
- voice: {
329
- enabled: false,
330
- transcriptionModel: "whisper-1",
331
- ttsModel: "gpt-4o-mini-tts",
332
- ttsVoice: "alloy",
333
- ttsFormat: "wav",
334
- },
335
306
  providers: { webSearch: "auto", image: "auto" },
336
307
  } satisfies Settings;
337
308
 
@@ -1170,10 +1141,6 @@ export class SettingsManager {
1170
1141
  await this.save();
1171
1142
  }
1172
1143
 
1173
- getGitToolEnabled(): boolean {
1174
- return this.settings.git?.enabled ?? false;
1175
- }
1176
-
1177
1144
  getPythonToolMode(): PythonToolMode {
1178
1145
  return this.settings.python?.toolMode ?? "both";
1179
1146
  }
@@ -1210,14 +1177,6 @@ export class SettingsManager {
1210
1177
  await this.save();
1211
1178
  }
1212
1179
 
1213
- async setGitToolEnabled(enabled: boolean): Promise<void> {
1214
- if (!this.globalSettings.git) {
1215
- this.globalSettings.git = {};
1216
- }
1217
- this.globalSettings.git.enabled = enabled;
1218
- await this.save();
1219
- }
1220
-
1221
1180
  getMCPProjectConfigEnabled(): boolean {
1222
1181
  return this.settings.mcp?.enableProjectConfig ?? true;
1223
1182
  }
@@ -1430,70 +1389,6 @@ export class SettingsManager {
1430
1389
  await this.save();
1431
1390
  }
1432
1391
 
1433
- getVoiceSettings(): Required<VoiceSettings> {
1434
- return {
1435
- enabled: this.settings.voice?.enabled ?? false,
1436
- transcriptionModel: this.settings.voice?.transcriptionModel ?? "whisper-1",
1437
- transcriptionLanguage: this.settings.voice?.transcriptionLanguage ?? "",
1438
- ttsModel: this.settings.voice?.ttsModel ?? "tts-1",
1439
- ttsVoice: this.settings.voice?.ttsVoice ?? "alloy",
1440
- ttsFormat: this.settings.voice?.ttsFormat ?? "wav",
1441
- };
1442
- }
1443
-
1444
- async setVoiceSettings(settings: VoiceSettings): Promise<void> {
1445
- this.globalSettings.voice = { ...this.globalSettings.voice, ...settings };
1446
- await this.save();
1447
- }
1448
-
1449
- getVoiceEnabled(): boolean {
1450
- return this.settings.voice?.enabled ?? false;
1451
- }
1452
-
1453
- async setVoiceEnabled(enabled: boolean): Promise<void> {
1454
- if (!this.globalSettings.voice) {
1455
- this.globalSettings.voice = {};
1456
- }
1457
- this.globalSettings.voice.enabled = enabled;
1458
- await this.save();
1459
- }
1460
-
1461
- getVoiceTtsModel(): string {
1462
- return this.settings.voice?.ttsModel ?? "gpt-4o-mini-tts";
1463
- }
1464
-
1465
- async setVoiceTtsModel(model: string): Promise<void> {
1466
- if (!this.globalSettings.voice) {
1467
- this.globalSettings.voice = {};
1468
- }
1469
- this.globalSettings.voice.ttsModel = model;
1470
- await this.save();
1471
- }
1472
-
1473
- getVoiceTtsVoice(): string {
1474
- return this.settings.voice?.ttsVoice ?? "alloy";
1475
- }
1476
-
1477
- async setVoiceTtsVoice(voice: string): Promise<void> {
1478
- if (!this.globalSettings.voice) {
1479
- this.globalSettings.voice = {};
1480
- }
1481
- this.globalSettings.voice.ttsVoice = voice;
1482
- await this.save();
1483
- }
1484
-
1485
- getVoiceTtsFormat(): "wav" | "mp3" | "opus" | "aac" | "flac" {
1486
- return this.settings.voice?.ttsFormat ?? "wav";
1487
- }
1488
-
1489
- async setVoiceTtsFormat(format: "wav" | "mp3" | "opus" | "aac" | "flac"): Promise<void> {
1490
- if (!this.globalSettings.voice) {
1491
- this.globalSettings.voice = {};
1492
- }
1493
- this.globalSettings.voice.ttsFormat = format;
1494
- await this.save();
1495
- }
1496
-
1497
1392
  // ═══════════════════════════════════════════════════════════════════════════
1498
1393
  // Status Line Settings
1499
1394
  // ═══════════════════════════════════════════════════════════════════════════
@@ -33,8 +33,6 @@ export class OutputSink {
33
33
  path: string;
34
34
  sink: Bun.FileSink;
35
35
  };
36
- #bytesWritten: number = 0;
37
- #pending: Promise<void> = Promise.resolve();
38
36
 
39
37
  readonly #allocateFilePath: () => string;
40
38
  readonly #spillThreshold: number;
@@ -54,15 +52,16 @@ export class OutputSink {
54
52
 
55
53
  async #pushSanitized(data: string): Promise<void> {
56
54
  this.#onChunk?.(data);
57
- const dataBytes = Buffer.byteLength(data);
58
- const overflow = dataBytes + this.#bytesWritten > this.#spillThreshold || this.#file != null;
55
+
56
+ const bufferOverflow = data.length + this.#buffer.length > this.#spillThreshold;
57
+ const overflow = this.#file || bufferOverflow;
59
58
 
60
59
  const sink = overflow ? await this.#fileSink() : null;
61
60
 
62
61
  this.#buffer += data;
63
62
  await sink?.write(data);
64
63
 
65
- if (this.#buffer.length > this.#spillThreshold) {
64
+ if (bufferOverflow) {
66
65
  this.#buffer = this.#buffer.slice(-this.#spillThreshold);
67
66
  }
68
67
  }
@@ -81,28 +80,21 @@ export class OutputSink {
81
80
 
82
81
  async push(chunk: string): Promise<void> {
83
82
  chunk = sanitizeText(chunk);
84
- const op = this.#pending.then(() => this.#pushSanitized(chunk));
85
- this.#pending = op.catch(() => {});
86
- await op;
83
+ await this.#pushSanitized(chunk);
87
84
  }
88
85
 
89
86
  createInput(): WritableStream<Uint8Array | string> {
90
- let decoder: TextDecoder | undefined;
91
- let finalize = async () => {};
87
+ const dec = new TextDecoder("utf-8", { ignoreBOM: true });
88
+ const finalize = async () => {
89
+ await this.push(dec.decode());
90
+ };
92
91
 
93
92
  return new WritableStream<Uint8Array | string>({
94
93
  write: async (chunk) => {
95
94
  if (typeof chunk === "string") {
96
95
  await this.push(chunk);
97
96
  } else {
98
- if (!decoder) {
99
- const dec = new TextDecoder("utf-8", { ignoreBOM: true });
100
- decoder = dec;
101
- finalize = async () => {
102
- await this.push(dec.decode());
103
- };
104
- }
105
- await this.push(decoder.decode(chunk, { stream: true }));
97
+ await this.push(dec.decode(chunk, { stream: true }));
106
98
  }
107
99
  },
108
100
  close: finalize,
@@ -111,7 +103,6 @@ export class OutputSink {
111
103
  }
112
104
 
113
105
  async dump(notice?: string): Promise<OutputResult> {
114
- await this.#pending;
115
106
  const noticeLine = notice ? `[${notice}]\n` : "";
116
107
 
117
108
  if (this.#file) {
@@ -7,7 +7,6 @@ export { exaTools } from "./exa/index";
7
7
  export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "./exa/types";
8
8
  export { type FindOperations, FindTool, type FindToolDetails, type FindToolOptions } from "./find";
9
9
  export { setPreferredImageProvider } from "./gemini-image";
10
- export { GitTool, type GitToolDetails } from "./git";
11
10
  export { type GrepOperations, GrepTool, type GrepToolDetails, type GrepToolOptions } from "./grep";
12
11
  export { type LsOperations, LsTool, type LsToolDetails, type LsToolOptions } from "./ls";
13
12
  export {
@@ -72,7 +71,6 @@ import { BashTool } from "./bash";
72
71
  import { CalculatorTool } from "./calculator";
73
72
  import { CompleteTool } from "./complete";
74
73
  import { FindTool } from "./find";
75
- import { GitTool } from "./git";
76
74
  import { GrepTool } from "./grep";
77
75
  import { LsTool } from "./ls";
78
76
  import { LspTool } from "./lsp/index";
@@ -132,7 +130,6 @@ export interface ToolSession {
132
130
  getEditFuzzyMatch(): boolean;
133
131
  getEditFuzzyThreshold?(): number;
134
132
  getEditPatchMode?(): boolean;
135
- getGitToolEnabled(): boolean;
136
133
  getBashInterceptorEnabled(): boolean;
137
134
  getBashInterceptorSimpleLsEnabled(): boolean;
138
135
  getBashInterceptorRules(): BashInterceptorRule[];
@@ -152,7 +149,6 @@ export const BUILTIN_TOOLS: Record<string, ToolFactory> = {
152
149
  ssh: loadSshTool,
153
150
  edit: (s) => new EditTool(s),
154
151
  find: (s) => new FindTool(s),
155
- git: GitTool.createIf,
156
152
  grep: (s) => new GrepTool(s),
157
153
  ls: (s) => new LsTool(s),
158
154
  lsp: LspTool.createIf,
@@ -40,7 +40,7 @@ function groupPreludeHelpers(helpers: PreludeHelper[]): PreludeCategory[] {
40
40
 
41
41
  export const pythonSchema = Type.Object({
42
42
  code: Type.String({ description: "Python code to execute" }),
43
- timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
43
+ timeoutMs: Type.Optional(Type.Number({ description: "Timeout in milliseconds (default: 30000)" })),
44
44
  workdir: Type.Optional(
45
45
  Type.String({ description: "Working directory for the command (default: current directory)" }),
46
46
  ),
@@ -151,7 +151,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
151
151
  throw new Error("Python tool requires a session when not using proxy executor");
152
152
  }
153
153
 
154
- const { code, timeout, workdir, reset } = params;
154
+ const { code, timeoutMs = 30000, workdir, reset } = params;
155
155
  const controller = new AbortController();
156
156
  const onAbort = () => controller.abort();
157
157
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -182,7 +182,7 @@ export class PythonTool implements AgentTool<typeof pythonSchema> {
182
182
  const sessionId = sessionFile ? `session:${sessionFile}:workdir:${commandCwd}` : `cwd:${commandCwd}`;
183
183
  const executorOptions: PythonExecutorOptions = {
184
184
  cwd: commandCwd,
185
- timeout: timeout ? timeout * 1000 : undefined,
185
+ timeoutMs,
186
186
  signal: controller.signal,
187
187
  sessionId,
188
188
  kernelMode: this.session.settings?.getPythonKernelMode?.() ?? "session",
package/src/index.ts CHANGED
@@ -201,8 +201,6 @@ export {
201
201
  type FindToolDetails,
202
202
  type FindToolOptions,
203
203
  formatSize,
204
- GitTool,
205
- type GitToolDetails,
206
204
  type GrepOperations,
207
205
  type GrepToolDetails,
208
206
  type GrepToolOptions,
@@ -83,7 +83,6 @@ const THINKING_DESCRIPTIONS: Record<ThinkingLevel, string> = {
83
83
  * - behavior: Core agent behavior (compaction, modes, retries, notifications)
84
84
  * - tools: Tool-specific settings (bash, git, python, edit, MCP, skills)
85
85
  * - display: Visual/UI settings (theme, images, thinking)
86
- * - voice: Voice mode and TTS settings
87
86
  * - ttsr: Time Traveling Stream Rules settings
88
87
  * - status: Status line configuration
89
88
  * - lsp: LSP integration settings
@@ -250,15 +249,6 @@ export const SETTINGS_DEFS: SettingDef[] = [
250
249
  get: (sm) => sm.getBashInterceptorSimpleLsEnabled(),
251
250
  set: (sm, v) => sm.setBashInterceptorSimpleLsEnabled(v),
252
251
  },
253
- {
254
- id: "gitTool",
255
- tab: "tools",
256
- type: "boolean",
257
- label: "Git tool",
258
- description: "Enable structured Git tool",
259
- get: (sm) => sm.getGitToolEnabled(),
260
- set: (sm, v) => sm.setGitToolEnabled(v),
261
- },
262
252
  {
263
253
  id: "pythonToolMode",
264
254
  tab: "tools",
@@ -494,66 +484,6 @@ export const SETTINGS_DEFS: SettingDef[] = [
494
484
  set: (sm, v) => sm.setShowHardwareCursor(v),
495
485
  },
496
486
 
497
- // ═══════════════════════════════════════════════════════════════════════════
498
- // Voice tab - Voice mode and TTS settings
499
- // ═══════════════════════════════════════════════════════════════════════════
500
- {
501
- id: "voiceEnabled",
502
- tab: "voice",
503
- type: "boolean",
504
- label: "Voice mode",
505
- description: "Enable realtime voice input/output (Ctrl+Y toggle, auto-send on silence)",
506
- get: (sm) => sm.getVoiceEnabled(),
507
- set: (sm, v) => sm.setVoiceEnabled(v),
508
- },
509
- {
510
- id: "voiceTtsModel",
511
- tab: "voice",
512
- type: "submenu",
513
- label: "TTS model",
514
- description: "Text-to-speech model for voice output",
515
- get: (sm) => sm.getVoiceTtsModel(),
516
- set: (sm, v) => sm.setVoiceTtsModel(v),
517
- getOptions: () => [
518
- { value: "gpt-4o-mini-tts", label: "GPT-4o Mini TTS", description: "Fast and efficient" },
519
- { value: "tts-1", label: "TTS-1", description: "Standard quality" },
520
- { value: "tts-1-hd", label: "TTS-1 HD", description: "Higher quality" },
521
- ],
522
- },
523
- {
524
- id: "voiceTtsVoice",
525
- tab: "voice",
526
- type: "submenu",
527
- label: "TTS voice",
528
- description: "Voice for text-to-speech output",
529
- get: (sm) => sm.getVoiceTtsVoice(),
530
- set: (sm, v) => sm.setVoiceTtsVoice(v),
531
- getOptions: () => [
532
- { value: "alloy", label: "Alloy", description: "Neutral" },
533
- { value: "echo", label: "Echo", description: "Male" },
534
- { value: "fable", label: "Fable", description: "British" },
535
- { value: "onyx", label: "Onyx", description: "Deep male" },
536
- { value: "nova", label: "Nova", description: "Female" },
537
- { value: "shimmer", label: "Shimmer", description: "Female" },
538
- ],
539
- },
540
- {
541
- id: "voiceTtsFormat",
542
- tab: "voice",
543
- type: "submenu",
544
- label: "TTS format",
545
- description: "Audio format for voice output",
546
- get: (sm) => sm.getVoiceTtsFormat(),
547
- set: (sm, v) => sm.setVoiceTtsFormat(v as "wav" | "mp3" | "opus" | "aac" | "flac"),
548
- getOptions: () => [
549
- { value: "wav", label: "WAV", description: "Uncompressed, best quality" },
550
- { value: "mp3", label: "MP3", description: "Compressed, widely compatible" },
551
- { value: "opus", label: "Opus", description: "Efficient compression" },
552
- { value: "aac", label: "AAC", description: "Apple-friendly" },
553
- { value: "flac", label: "FLAC", description: "Lossless compression" },
554
- ],
555
- },
556
-
557
487
  // ═══════════════════════════════════════════════════════════════════════════
558
488
  // TTSR tab - Time Traveling Stream Rules
559
489
  // ═══════════════════════════════════════════════════════════════════════════
@@ -117,7 +117,6 @@ const SETTINGS_TABS: Tab[] = [
117
117
  { id: "behavior", label: "Behavior" },
118
118
  { id: "tools", label: "Tools" },
119
119
  { id: "display", label: "Display" },
120
- { id: "voice", label: "Voice" },
121
120
  { id: "ttsr", label: "TTSR" },
122
121
  { id: "status", label: "Status" },
123
122
  { id: "lsp", label: "LSP" },
@@ -68,7 +68,6 @@ export class EventController {
68
68
  getSymbolTheme().spinnerFrames,
69
69
  );
70
70
  this.ctx.statusContainer.addChild(this.ctx.loadingAnimation);
71
- this.ctx.startVoiceProgressTimer();
72
71
  this.ctx.ui.requestRender();
73
72
  break;
74
73
 
@@ -250,7 +249,6 @@ export class EventController {
250
249
  }
251
250
 
252
251
  case "agent_end":
253
- this.ctx.stopVoiceProgressTimer();
254
252
  if (this.ctx.loadingAnimation) {
255
253
  this.ctx.loadingAnimation.stop();
256
254
  this.ctx.loadingAnimation = undefined;
@@ -262,15 +260,6 @@ export class EventController {
262
260
  this.ctx.streamingMessage = undefined;
263
261
  }
264
262
  this.ctx.pendingTools.clear();
265
- if (this.ctx.settingsManager.getVoiceEnabled() && this.ctx.voiceAutoModeEnabled) {
266
- const lastAssistant = this.ctx.findLastAssistantMessage();
267
- if (lastAssistant && lastAssistant.stopReason !== "aborted" && lastAssistant.stopReason !== "error") {
268
- const text = this.ctx.extractAssistantText(lastAssistant);
269
- if (text) {
270
- this.ctx.voiceSupervisor.notifyResult(text);
271
- }
272
- }
273
- }
274
263
  this.ctx.ui.requestRender();
275
264
  this.sendCompletionNotification();
276
265
  break;
@@ -199,15 +199,6 @@ export class SelectorController {
199
199
  this.ctx.ui.invalidate();
200
200
  break;
201
201
  }
202
- case "voiceEnabled": {
203
- if (!value) {
204
- this.ctx.voiceAutoModeEnabled = false;
205
- this.ctx.stopVoiceProgressTimer();
206
- void this.ctx.voiceSupervisor.stop();
207
- this.ctx.setVoiceStatus(undefined);
208
- }
209
- break;
210
- }
211
202
  case "statusLinePreset":
212
203
  case "statusLineSeparator":
213
204
  case "statusLineShowHooks":