@goodandready/dsh-voice 0.9.24 → 0.9.25
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/lib/updater.js +8 -61
- package/package.json +1 -1
package/lib/updater.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// Implements canonical DSH plugin-updater specification.
|
|
3
3
|
|
|
4
4
|
import { spawn } from 'node:child_process';
|
|
5
|
-
import { existsSync, readFileSync,
|
|
5
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
6
6
|
import { readFile } from 'node:fs/promises';
|
|
7
7
|
import { homedir } from 'node:os';
|
|
8
8
|
import { basename, dirname, isAbsolute, resolve } from 'node:path';
|
|
@@ -196,67 +196,16 @@ export function isProcessAlive(pid) {
|
|
|
196
196
|
|
|
197
197
|
export function checkProfileLock(profileDir) {
|
|
198
198
|
const lockPath = resolve(profileDir, 'package.json.lock');
|
|
199
|
-
if (!existsSync(lockPath)) return { locked: false };
|
|
200
|
-
let initialStat;
|
|
201
|
-
try { initialStat = statSync(lockPath); } catch { return { locked: false }; }
|
|
202
|
-
const pid = readLockPid(lockPath);
|
|
203
|
-
if (pid !== null) {
|
|
204
|
-
if (isProcessAlive(pid)) {
|
|
205
|
-
return { locked: true, pid };
|
|
206
|
-
}
|
|
207
|
-
// Stale lock: PID is not running.
|
|
208
|
-
// Verify before unlinking: re-check PID and stat to ensure a concurrent live successor
|
|
209
|
-
// was not written during the check (#205).
|
|
210
|
-
try {
|
|
211
|
-
const p1 = readLockPid(lockPath);
|
|
212
|
-
if (p1 !== null && isProcessAlive(p1)) return { locked: true, pid: p1 };
|
|
213
|
-
const p2 = readLockPid(lockPath);
|
|
214
|
-
if (p2 !== null && isProcessAlive(p2)) return { locked: true, pid: p2 };
|
|
215
|
-
const p3 = readLockPid(lockPath);
|
|
216
|
-
if (p3 !== null && isProcessAlive(p3)) return { locked: true, pid: p3 };
|
|
217
|
-
const currentStat = statSync(lockPath);
|
|
218
|
-
if (currentStat.mtimeMs !== initialStat.mtimeMs || currentStat.size !== initialStat.size) {
|
|
219
|
-
const live = readLockPid(lockPath);
|
|
220
|
-
if (live !== null && isProcessAlive(live)) return { locked: true, pid: live };
|
|
221
|
-
}
|
|
222
|
-
const finalPid = readLockPid(lockPath);
|
|
223
|
-
if (finalPid !== null && isProcessAlive(finalPid)) {
|
|
224
|
-
return { locked: true, pid: finalPid };
|
|
225
|
-
}
|
|
226
|
-
const postStat = statSync(lockPath);
|
|
227
|
-
if (postStat.mtimeMs !== initialStat.mtimeMs || postStat.size !== initialStat.size) {
|
|
228
|
-
const live = readLockPid(lockPath);
|
|
229
|
-
if (live !== null && isProcessAlive(live)) return { locked: true, pid: live };
|
|
230
|
-
}
|
|
231
|
-
const postPid = readLockPid(lockPath);
|
|
232
|
-
if (postPid !== null && isProcessAlive(postPid)) {
|
|
233
|
-
return { locked: true, pid: postPid };
|
|
234
|
-
}
|
|
235
|
-
if (p1 === pid && p2 === pid && p3 === pid && finalPid === pid && postPid === pid) {
|
|
236
|
-
unlinkSync(lockPath);
|
|
237
|
-
return { locked: false, cleanedStale: true };
|
|
238
|
-
}
|
|
239
|
-
return { locked: false };
|
|
240
|
-
} catch {
|
|
241
|
-
if (!existsSync(lockPath)) return { locked: false };
|
|
242
|
-
const currentPid = readLockPid(lockPath);
|
|
243
|
-
if (currentPid !== null && isProcessAlive(currentPid)) {
|
|
244
|
-
return { locked: true, pid: currentPid };
|
|
245
|
-
}
|
|
246
|
-
return { locked: false };
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// Lockfile without valid PID: check age (> 10 min)
|
|
250
199
|
try {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
return { locked: false
|
|
200
|
+
statSync(lockPath);
|
|
201
|
+
} catch (err) {
|
|
202
|
+
if (err && err.code === 'ENOENT') {
|
|
203
|
+
return { locked: false };
|
|
255
204
|
}
|
|
256
|
-
return { locked: true, pid: null };
|
|
257
|
-
} catch {
|
|
258
|
-
return { locked: false };
|
|
205
|
+
return { locked: true, pid: null, error: err?.code || 'EUNKNOWN' };
|
|
259
206
|
}
|
|
207
|
+
const pid = readLockPid(lockPath);
|
|
208
|
+
return { locked: true, pid };
|
|
260
209
|
}
|
|
261
210
|
|
|
262
211
|
async function installExact(target, packageSpec, options) {
|
|
@@ -291,13 +240,11 @@ async function installExact(target, packageSpec, options) {
|
|
|
291
240
|
child.once('error', error => {
|
|
292
241
|
clearTimeout(timeoutTimer);
|
|
293
242
|
if (killTimer) clearTimeout(killTimer);
|
|
294
|
-
checkProfileLock(target.profileDir);
|
|
295
243
|
reject(error);
|
|
296
244
|
});
|
|
297
245
|
child.once('exit', code => {
|
|
298
246
|
clearTimeout(timeoutTimer);
|
|
299
247
|
if (killTimer) clearTimeout(killTimer);
|
|
300
|
-
checkProfileLock(target.profileDir);
|
|
301
248
|
if (timedOut) {
|
|
302
249
|
reject(new Error('Update timed out; use the normal DSH update flow.'));
|
|
303
250
|
} else if (code === 0) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-voice",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.25",
|
|
4
4
|
"description": "Voice input for DeepSeek Harness: dictation chunked by pauses and voice messages, each with its own provider fallback chain (Deepgram, Groq, HuggingFace, local whisper.cpp, plus any OpenAI-compatible API of your own).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|