opencode-interrupt-plugin 0.4.36 → 0.4.38

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/dist/index.js CHANGED
@@ -146,70 +146,16 @@ async function transcribeAPI() {
146
146
  return null;
147
147
  }
148
148
  }
149
- async function transcribeAndSend(sessionID, directory, api, modelPath) {
149
+ async function transcribeAndSend(sessionID, client, modelPath) {
150
150
  pttStopRecording();
151
- if (!existsSync(RECORDING_FILE)) {
152
- api.ui.toast({ variant: "warning", title: "PTT", message: "No audio captured" });
153
- return;
154
- }
155
- const hasApiKey = !!process.env.OPENAI_API_KEY;
156
- api.ui.toast({ variant: "info", title: "PTT", message: hasApiKey ? "⏳ Transcribing via OpenAI API..." : "⏳ Transcribing with Whisper..." });
157
- let text = null;
158
- if (hasApiKey) {
159
- text = await transcribeAPI();
160
- if (!text)
161
- text = await transcribeLocal(modelPath);
162
- }
163
- else {
164
- text = await transcribeLocal(modelPath);
165
- if (!text)
166
- text = await transcribeAPI();
167
- }
168
- if (!text) {
169
- api.ui.toast({ variant: "error", title: "PTT", message: "❌ Install whisper: run scripts/install-whisper.sh, or set OPENAI_API_KEY" });
170
- try {
171
- unlinkSync(RECORDING_FILE);
172
- }
173
- catch { /* ignore */ }
174
- return;
175
- }
176
- const { text: clean, polished } = await processTranscription(text);
177
- if (!clean) {
178
- api.ui.toast({ variant: "warning", title: "PTT", message: "⚠️ No meaningful text in recording" });
179
- try {
180
- unlinkSync(RECORDING_FILE);
181
- }
182
- catch { /* ignore */ }
183
- return;
184
- }
185
- try {
186
- unlinkSync(RECORDING_FILE);
187
- }
188
- catch { /* ignore */ }
189
151
  if (!sessionID) {
190
- api.ui.toast({ variant: "warning", title: "PTT", message: "⚠️ Open a session first, then type /ptt" });
152
+ await client.tui.showToast({ body: { title: "PTT", message: "⚠️ Open a session first, then type /ptt", variant: "warning", duration: 5000 } });
191
153
  return;
192
154
  }
193
155
  if (!checkInterruptCap()) {
194
- api.ui.toast({ variant: "warning", title: "PTT", message: "⚠️ Free limit (20/day) reached — purchase Pro for unlimited interrupts" });
195
- try {
196
- unlinkSync(RECORDING_FILE);
197
- }
198
- catch { /* ignore */ }
156
+ await client.tui.showToast({ body: { title: "PTT", message: "⚠️ Free limit (20/day) reached — purchase Pro for unlimited interrupts", variant: "warning", duration: 6000 } });
199
157
  return;
200
158
  }
201
- const state = getSessionState(sessionID);
202
- if (!state.interruptCounted)
203
- incrementInterruptCount();
204
- else
205
- updateSessionState(sessionID, { interruptCounted: false });
206
- api.ui.toast({ variant: "info", title: "PTT", message: polished ? "✨ Sending polished transcript..." : "✉️ Sending transcript..." });
207
- await api.client.session.prompt({ sessionID, directory, parts: [{ type: "text", text: clean }] });
208
- const preview = clean.length > 80 ? clean.slice(0, 77) + "..." : clean;
209
- api.ui.toast({ variant: "success", title: "PTT", message: `✅ Sent: "${preview}"` });
210
- }
211
- async function transcribeAndSendV1(sessionID, client, modelPath) {
212
- pttStopRecording();
213
159
  if (!existsSync(RECORDING_FILE)) {
214
160
  await client.tui.showToast({ body: { title: "PTT", message: "⚠️ No audio captured — try again", variant: "warning" } });
215
161
  return;
@@ -229,37 +175,17 @@ async function transcribeAndSendV1(sessionID, client, modelPath) {
229
175
  }
230
176
  if (!text) {
231
177
  await client.tui.showToast({ body: { title: "PTT", message: "❌ Install whisper: run scripts/install-whisper.sh, or set OPENAI_API_KEY", variant: "error", duration: 8000 } });
232
- try {
233
- unlinkSync(RECORDING_FILE);
234
- }
235
- catch { /* ignore */ }
236
178
  return;
237
179
  }
238
180
  const { text: clean, polished } = await processTranscription(text);
239
181
  if (!clean) {
240
182
  await client.tui.showToast({ body: { title: "PTT", message: "⚠️ No meaningful text in recording", variant: "warning", duration: 4000 } });
241
- try {
242
- unlinkSync(RECORDING_FILE);
243
- }
244
- catch { /* ignore */ }
245
183
  return;
246
184
  }
247
185
  try {
248
186
  unlinkSync(RECORDING_FILE);
249
187
  }
250
188
  catch { /* ignore */ }
251
- if (!sessionID) {
252
- await client.tui.showToast({ body: { title: "PTT", message: "⚠️ Open a session first, then type /ptt", variant: "warning", duration: 5000 } });
253
- return;
254
- }
255
- if (!checkInterruptCap()) {
256
- await client.tui.showToast({ body: { title: "PTT", message: "⚠️ Free limit (20/day) reached — purchase Pro for unlimited interrupts", variant: "warning", duration: 6000 } });
257
- try {
258
- unlinkSync(RECORDING_FILE);
259
- }
260
- catch { /* ignore */ }
261
- return;
262
- }
263
189
  const state = getSessionState(sessionID);
264
190
  if (!state.interruptCounted)
265
191
  incrementInterruptCount();
@@ -468,7 +394,7 @@ export const InterruptPlugin = (userConfig = {}) => {
468
394
  const sessionID = cmdInput.sessionID;
469
395
  if (pttActive) {
470
396
  pttActive = false;
471
- await transcribeAndSendV1(sessionID, client, config.whisperModel);
397
+ await transcribeAndSend(sessionID, client, config.whisperModel);
472
398
  }
473
399
  else {
474
400
  if (!checkInterruptCap()) {
@@ -2,6 +2,11 @@ const POLAR_ORG_ID = '166f4429-84b8-4e41-9c74-eff1b8724873';
2
2
  const POLAR_VALIDATE_URL = 'https://api.polar.sh/v1/customer-portal/license-keys/validate';
3
3
  const POLAR_ACTIVATE_URL = 'https://api.polar.sh/v1/customer-portal/license-keys/activate';
4
4
  const OFFLINE_GRACE_DAYS = 7;
5
+ async function timeoutSignal(ms) {
6
+ const ctrl = new AbortController();
7
+ setTimeout(() => ctrl.abort(), ms);
8
+ return ctrl.signal;
9
+ }
5
10
  export async function activateLicense(key, machineLabel) {
6
11
  try {
7
12
  const response = await fetch(POLAR_ACTIVATE_URL, {
@@ -13,7 +18,7 @@ export async function activateLicense(key, machineLabel) {
13
18
  label: machineLabel,
14
19
  conditions: { major_version: 1 },
15
20
  }),
16
- signal: AbortSignal.timeout(8000),
21
+ signal: await timeoutSignal(8000),
17
22
  });
18
23
  if (response.status === 200) {
19
24
  const data = await response.json();
@@ -49,7 +54,7 @@ export async function validateLicense(key, activationId) {
49
54
  activation_id: activationId,
50
55
  conditions: { major_version: 1 },
51
56
  }),
52
- signal: AbortSignal.timeout(5000),
57
+ signal: await timeoutSignal(5000),
53
58
  });
54
59
  if (response.status === 200) {
55
60
  const data = await response.json();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-interrupt-plugin",
3
- "version": "0.4.36",
3
+ "version": "0.4.38",
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",