opencode-interrupt-plugin 0.4.10 → 0.4.12

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 (2) hide show
  1. package/dist/index.js +46 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -8,6 +8,7 @@ import { VoiceOverlapDetector } from './audio/overlap.js';
8
8
  import { detectTextInterruption } from './detector.js';
9
9
  import { TTSStreamer } from './tts/index.js';
10
10
  let activeSessionId = null;
11
+ let pendingInterrupt = null;
11
12
  const TTS_COMMANDS = [
12
13
  { name: 'tts-on', description: 'Enable streaming TTS', template: 'TTS enabled.' },
13
14
  { name: 'tts-off', description: 'Disable streaming TTS', template: 'TTS disabled.' },
@@ -51,7 +52,8 @@ export const InterruptPlugin = (userConfig = {}) => {
51
52
  }, () => ttsStreamer.getPartialContent());
52
53
  overlapDetector.on('voice-overlap', (event) => {
53
54
  if (!activeSessionId) {
54
- debug(`[interrupt] Voice overlap event but no active session, ignoring`);
55
+ pendingInterrupt = event;
56
+ debug(`[interrupt] Voice overlap event buffered (no active session)`);
55
57
  return;
56
58
  }
57
59
  debug(`[interrupt] Voice overlap detected (RMS: ${event.rmsLevel.toFixed(4)})`);
@@ -112,11 +114,12 @@ export const InterruptPlugin = (userConfig = {}) => {
112
114
  if (!msg || !msg.role)
113
115
  return;
114
116
  if (msg.role === 'assistant') {
117
+ const state = getSessionState(sessionId);
115
118
  const content = extractText(parts);
116
119
  updateSessionState(sessionId, {
117
120
  lastAssistantContent: content,
118
121
  lastAssistantTimestamp: Date.now(),
119
- wasInterrupted: false,
122
+ wasInterrupted: state.awaitingCorrection ? state.wasInterrupted : false,
120
123
  });
121
124
  return;
122
125
  }
@@ -141,6 +144,17 @@ export const InterruptPlugin = (userConfig = {}) => {
141
144
  if (!sessionId)
142
145
  return;
143
146
  activeSessionId = sessionId;
147
+ if (pendingInterrupt) {
148
+ updateSessionState(sessionId, {
149
+ wasInterrupted: true,
150
+ partialContentAtInterrupt: pendingInterrupt.partialTTSContent,
151
+ interruptTimestamp: pendingInterrupt.overlapTimestamp,
152
+ awaitingCorrection: true,
153
+ interruptSource: 'voice',
154
+ });
155
+ debug(`[interrupt] Applied buffered voice overlap to session ${sessionId}`);
156
+ pendingInterrupt = null;
157
+ }
144
158
  const sessionState = getSessionState(sessionId);
145
159
  const userMessage = extractUserMessage(input);
146
160
  if (!userMessage)
@@ -202,10 +216,40 @@ export const InterruptPlugin = (userConfig = {}) => {
202
216
  if (isTTSTool(toolName)) {
203
217
  onTTSEnd();
204
218
  }
219
+ if (config.tts && isWriteTool(toolName)) {
220
+ const text = extractToolOutput(output);
221
+ if (text) {
222
+ debug(`[interrupt] Tool "${toolName}" output captured (${text.length} chars) for TTS`);
223
+ ttsStreamer.onTextChunk({
224
+ messageID: `tool-${toolName}-${Date.now()}`,
225
+ type: 'text',
226
+ text,
227
+ });
228
+ }
229
+ }
205
230
  },
206
231
  };
207
232
  };
208
233
  };
234
+ const WRITE_TOOL_NAMES = ['write', 'create', 'edit', 'overwrite', 'file.write', 'file.create', 'file.edit', 'file.overwrite', 'append'];
235
+ function isWriteTool(name) {
236
+ return WRITE_TOOL_NAMES.includes(name.toLowerCase());
237
+ }
238
+ function extractToolOutput(output) {
239
+ if (!output)
240
+ return '';
241
+ if (typeof output === 'string')
242
+ return output;
243
+ if (typeof output.result === 'string')
244
+ return output.result;
245
+ if (output.result?.content)
246
+ return output.result.content;
247
+ if (output.content)
248
+ return output.content;
249
+ if (output.text)
250
+ return output.text;
251
+ return '';
252
+ }
209
253
  function extractUserMessage(input) {
210
254
  try {
211
255
  const messages = input.messages || [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-interrupt-plugin",
3
- "version": "0.4.10",
3
+ "version": "0.4.12",
4
4
  "description": "Streaming TTS + voice interruption for OpenCode. Speaks responses as they arrive and detects when you talk over it.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",