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 +4 -78
- package/dist/license/validator.js +7 -2
- package/package.json +1 -1
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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.
|
|
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",
|