@techsologic/unolock-agent 0.1.38 → 0.1.39
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/bin/unolock-agent.js +114 -14
- package/package.json +1 -1
package/bin/unolock-agent.js
CHANGED
|
@@ -7,9 +7,12 @@ const path = require("path");
|
|
|
7
7
|
const https = require("https");
|
|
8
8
|
const { spawn } = require("child_process");
|
|
9
9
|
|
|
10
|
-
const PACKAGE_VERSION = "0.1.
|
|
11
|
-
const FALLBACK_BINARY_VERSION = "0.1.
|
|
10
|
+
const PACKAGE_VERSION = "0.1.39";
|
|
11
|
+
const FALLBACK_BINARY_VERSION = "0.1.39";
|
|
12
12
|
const REPO = "TechSologic/unolock-agent";
|
|
13
|
+
const INSTALL_LOCK_TIMEOUT_MS = 120000;
|
|
14
|
+
const INSTALL_LOCK_STALE_MS = 300000;
|
|
15
|
+
const INSTALL_LOCK_POLL_MS = 100;
|
|
13
16
|
const TOP_LEVEL_USAGE = `usage: unolock-agent [-h] [--version] {register,set-agent-pin,list-spaces,get-current-space,set-current-space,list-records,list-notes,list-checklists,get-record,create-note,update-note,append-note,rename-record,create-checklist,set-checklist-item-done,add-checklist-item,remove-checklist-item,list-files,get-file,download-file,upload-file,rename-file,replace-file,delete-file,tpm-diagnose,tpm-check,self-test,mcp} ...
|
|
14
17
|
|
|
15
18
|
UnoLock Agent commands.
|
|
@@ -79,6 +82,10 @@ function metadataPath() {
|
|
|
79
82
|
return path.join(cacheRoot(), "unolock-agent", "release.json");
|
|
80
83
|
}
|
|
81
84
|
|
|
85
|
+
function installLockPath() {
|
|
86
|
+
return path.join(cacheRoot(), "unolock-agent", "install.lock");
|
|
87
|
+
}
|
|
88
|
+
|
|
82
89
|
function binaryPath(releaseVersion) {
|
|
83
90
|
const { executable } = platformAssetInfo();
|
|
84
91
|
return path.join(cacheRoot(), "unolock-agent", releaseVersion, executable);
|
|
@@ -96,6 +103,12 @@ function ensureDir(dir) {
|
|
|
96
103
|
fs.mkdirSync(dir, { recursive: true, mode: 0o755 });
|
|
97
104
|
}
|
|
98
105
|
|
|
106
|
+
function sleep(ms) {
|
|
107
|
+
return new Promise((resolve) => {
|
|
108
|
+
setTimeout(resolve, ms);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
99
112
|
function fetchToFile(url, dest) {
|
|
100
113
|
return new Promise((resolve, reject) => {
|
|
101
114
|
const temp = `${dest}.download`;
|
|
@@ -215,8 +228,10 @@ function readReleaseMetadata() {
|
|
|
215
228
|
|
|
216
229
|
function writeReleaseMetadata(releaseVersion) {
|
|
217
230
|
ensureDir(path.dirname(metadataPath()));
|
|
231
|
+
const dest = metadataPath();
|
|
232
|
+
const temp = `${dest}.tmp-${process.pid}`;
|
|
218
233
|
fs.writeFileSync(
|
|
219
|
-
|
|
234
|
+
temp,
|
|
220
235
|
JSON.stringify(
|
|
221
236
|
{
|
|
222
237
|
releaseVersion,
|
|
@@ -227,6 +242,7 @@ function writeReleaseMetadata(releaseVersion) {
|
|
|
227
242
|
),
|
|
228
243
|
"utf8"
|
|
229
244
|
);
|
|
245
|
+
fs.renameSync(temp, dest);
|
|
230
246
|
}
|
|
231
247
|
|
|
232
248
|
function cachedReleaseVersion() {
|
|
@@ -266,16 +282,88 @@ async function resolveReleaseVersion() {
|
|
|
266
282
|
return FALLBACK_BINARY_VERSION;
|
|
267
283
|
}
|
|
268
284
|
|
|
285
|
+
function removeIfStale(lockPath) {
|
|
286
|
+
let stats;
|
|
287
|
+
try {
|
|
288
|
+
stats = fs.statSync(lockPath);
|
|
289
|
+
} catch (error) {
|
|
290
|
+
if (error && error.code === "ENOENT") {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
throw error;
|
|
294
|
+
}
|
|
295
|
+
if (Date.now() - stats.mtimeMs < INSTALL_LOCK_STALE_MS) {
|
|
296
|
+
return false;
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
fs.unlinkSync(lockPath);
|
|
300
|
+
return true;
|
|
301
|
+
} catch (error) {
|
|
302
|
+
if (error && error.code === "ENOENT") {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
if (error && error.code === "EPERM") {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function acquireInstallLock() {
|
|
313
|
+
const lockPath = installLockPath();
|
|
314
|
+
ensureDir(path.dirname(lockPath));
|
|
315
|
+
const deadline = Date.now() + INSTALL_LOCK_TIMEOUT_MS;
|
|
316
|
+
while (true) {
|
|
317
|
+
try {
|
|
318
|
+
const fd = fs.openSync(lockPath, "wx", 0o600);
|
|
319
|
+
fs.writeFileSync(
|
|
320
|
+
fd,
|
|
321
|
+
JSON.stringify({ pid: process.pid, createdAt: Date.now() }),
|
|
322
|
+
"utf8"
|
|
323
|
+
);
|
|
324
|
+
return () => {
|
|
325
|
+
try {
|
|
326
|
+
fs.closeSync(fd);
|
|
327
|
+
} catch {}
|
|
328
|
+
try {
|
|
329
|
+
fs.unlinkSync(lockPath);
|
|
330
|
+
} catch {}
|
|
331
|
+
};
|
|
332
|
+
} catch (error) {
|
|
333
|
+
if (!error || error.code !== "EEXIST") {
|
|
334
|
+
throw error;
|
|
335
|
+
}
|
|
336
|
+
removeIfStale(lockPath);
|
|
337
|
+
if (Date.now() >= deadline) {
|
|
338
|
+
throw new Error("Timed out waiting for the UnoLock agent install lock");
|
|
339
|
+
}
|
|
340
|
+
await sleep(INSTALL_LOCK_POLL_MS);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
269
345
|
async function ensureBinary() {
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
346
|
+
const cached = cachedReleaseVersion();
|
|
347
|
+
if (cached) {
|
|
348
|
+
const dest = binaryPath(cached);
|
|
349
|
+
if (fs.existsSync(dest)) {
|
|
350
|
+
return { dest, releaseVersion: cached };
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const releaseLock = await acquireInstallLock();
|
|
354
|
+
try {
|
|
355
|
+
const releaseVersion = await resolveReleaseVersion();
|
|
356
|
+
const dest = binaryPath(releaseVersion);
|
|
357
|
+
if (fs.existsSync(dest)) {
|
|
358
|
+
return { dest, releaseVersion };
|
|
359
|
+
}
|
|
360
|
+
ensureDir(path.dirname(dest));
|
|
361
|
+
process.stderr.write(`Downloading UnoLock agent ${releaseVersion} for ${process.platform}/${process.arch}...\n`);
|
|
362
|
+
await fetchToFile(binaryUrl(releaseVersion), dest);
|
|
273
363
|
return { dest, releaseVersion };
|
|
364
|
+
} finally {
|
|
365
|
+
releaseLock();
|
|
274
366
|
}
|
|
275
|
-
ensureDir(path.dirname(dest));
|
|
276
|
-
process.stderr.write(`Downloading UnoLock agent ${releaseVersion} for ${process.platform}/${process.arch}...\n`);
|
|
277
|
-
await fetchToFile(binaryUrl(releaseVersion), dest);
|
|
278
|
-
return { dest, releaseVersion };
|
|
279
367
|
}
|
|
280
368
|
|
|
281
369
|
async function main() {
|
|
@@ -311,7 +399,19 @@ async function main() {
|
|
|
311
399
|
});
|
|
312
400
|
}
|
|
313
401
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
402
|
+
if (require.main === module) {
|
|
403
|
+
main().catch((error) => {
|
|
404
|
+
process.stderr.write(`${error.message}\n`);
|
|
405
|
+
process.exit(1);
|
|
406
|
+
});
|
|
407
|
+
} else {
|
|
408
|
+
module.exports = {
|
|
409
|
+
acquireInstallLock,
|
|
410
|
+
compareVersions,
|
|
411
|
+
ensureBinary,
|
|
412
|
+
installLockPath,
|
|
413
|
+
metadataPath,
|
|
414
|
+
sleep,
|
|
415
|
+
writeReleaseMetadata,
|
|
416
|
+
};
|
|
417
|
+
}
|