@inaiii/pi-remote-helper 0.3.0 → 0.3.1
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/cli/lock.mjs +38 -11
- package/native/darwin-arm64/manifest.json +5 -5
- package/native/darwin-arm64/pi-remote-helper +0 -0
- package/native/darwin-arm64/pi-remote-launch-wrapper +0 -0
- package/native/darwin-x64/manifest.json +5 -5
- package/native/darwin-x64/pi-remote-helper +0 -0
- package/native/darwin-x64/pi-remote-launch-wrapper +0 -0
- package/package.json +2 -2
package/cli/lock.mjs
CHANGED
|
@@ -2,28 +2,55 @@ import { constants } from 'node:fs';
|
|
|
2
2
|
import { open } from 'node:fs/promises';
|
|
3
3
|
import { spawn } from 'node:child_process';
|
|
4
4
|
|
|
5
|
+
const lockMessages = {
|
|
6
|
+
MAINTENANCE_LOCK_FILE: 'Maintenance lock file is unsafe or inaccessible. Check private installation permissions and storage.',
|
|
7
|
+
MAINTENANCE_LOCK_UNAVAILABLE: 'Maintenance lock utility is unavailable. macOS requires lockf; Linux requires flock.',
|
|
8
|
+
MAINTENANCE_LOCK_BUSY: 'Another maintenance operation is active. Retry after it finishes; do not delete the lock file.',
|
|
9
|
+
MAINTENANCE_LOCK_FAILED: 'Maintenance lock did not become ready. Check the local lock and Unix shell utilities.',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export class MaintenanceLockError extends Error {
|
|
13
|
+
constructor(code) { super(lockMessages[code]); this.code = code; }
|
|
14
|
+
}
|
|
15
|
+
|
|
5
16
|
// Keep the inode: unlinking a released lock can let two callers lock different
|
|
6
17
|
// files. Kernel ownership ends when the temporary holder loses its stdin pipe,
|
|
7
18
|
// including when the maintenance process crashes.
|
|
8
19
|
export async function acquireMaintenanceLock(path) {
|
|
9
|
-
const file = await open(path, constants.O_CREAT | constants.O_WRONLY | constants.O_NOFOLLOW, 0o600);
|
|
10
20
|
try {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
const file = await open(path, constants.O_CREAT | constants.O_WRONLY | constants.O_NOFOLLOW, 0o600);
|
|
22
|
+
try {
|
|
23
|
+
const info = await file.stat();
|
|
24
|
+
if (!info.isFile() || info.nlink !== 1 || typeof process.getuid !== 'function' || info.uid !== process.getuid() || info.mode & 0o077) throw new MaintenanceLockError('MAINTENANCE_LOCK_FILE');
|
|
25
|
+
} finally { await file.close(); }
|
|
26
|
+
} catch { throw new MaintenanceLockError('MAINTENANCE_LOCK_FILE'); }
|
|
27
|
+
const script = '[ -x /bin/cat ] || exit 69; printf "ready\\n"; exec /bin/cat >/dev/null';
|
|
15
28
|
const holder = process.platform === 'darwin'
|
|
16
29
|
? spawn('/usr/bin/lockf', ['-k', '-t', '0', path, '/bin/sh', '-c', script], { stdio: ['pipe', 'pipe', 'ignore'] })
|
|
17
|
-
: spawn('flock', ['-n', path, '/bin/sh', '-c', script], { stdio: ['pipe', 'pipe', 'ignore'] });
|
|
30
|
+
: spawn('flock', ['-n', '-E', '75', path, '/bin/sh', '-c', script], { stdio: ['pipe', 'pipe', 'ignore'] });
|
|
18
31
|
holder.stdin.on('error', () => {});
|
|
19
32
|
const exited = new Promise(resolve => { holder.once('close', resolve); holder.once('error', resolve); });
|
|
20
33
|
try {
|
|
21
34
|
await new Promise((resolve, reject) => {
|
|
22
|
-
const timer = setTimeout(() =>
|
|
23
|
-
const finish = (error) => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
35
|
+
const timer = setTimeout(() => finish(new MaintenanceLockError('MAINTENANCE_LOCK_FAILED')), 5000);
|
|
36
|
+
const finish = (error) => {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
holder.stdout.off('data', ready); holder.off('error', failed); holder.off('close', closed);
|
|
39
|
+
error ? reject(error) : resolve();
|
|
40
|
+
};
|
|
41
|
+
let output = '';
|
|
42
|
+
const ready = chunk => {
|
|
43
|
+
output += chunk.toString();
|
|
44
|
+
if (output === 'ready\n') finish();
|
|
45
|
+
else if (!'ready\n'.startsWith(output)) finish(new MaintenanceLockError('MAINTENANCE_LOCK_FAILED'));
|
|
46
|
+
};
|
|
47
|
+
const failed = error => finish(new MaintenanceLockError(error.code === 'ENOENT' ? 'MAINTENANCE_LOCK_UNAVAILABLE' : 'MAINTENANCE_LOCK_FAILED'));
|
|
48
|
+
// lockf uses EX_TEMPFAIL for contention; flock's conflict exit is set to
|
|
49
|
+
// the same value. Other early exits do not prove another owner exists.
|
|
50
|
+
const closed = code => finish(new MaintenanceLockError(code === 75 ? 'MAINTENANCE_LOCK_BUSY' : 'MAINTENANCE_LOCK_FAILED'));
|
|
51
|
+
holder.stdout.on('data', ready);
|
|
52
|
+
holder.once('error', failed);
|
|
53
|
+
holder.once('close', closed);
|
|
27
54
|
});
|
|
28
55
|
} catch (error) {
|
|
29
56
|
holder.stdin.end();
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.3.
|
|
2
|
+
"version": "0.3.1",
|
|
3
3
|
"platform": "darwin",
|
|
4
4
|
"arch": "arm64",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"builtAt": "2026-10-
|
|
5
|
+
"gitCommit": "100e480b2e58ee1e68fed4c1d34bc6db5b9f471f",
|
|
6
|
+
"builtAt": "2026-10-06T06:10:23.000Z",
|
|
7
7
|
"sha256": {
|
|
8
|
-
"pi-remote-helper": "
|
|
9
|
-
"pi-remote-launch-wrapper": "
|
|
8
|
+
"pi-remote-helper": "6724620b1b6055770448171ea2db67a9e841bd3b86dc5c17fa4f9f0f4a967860",
|
|
9
|
+
"pi-remote-launch-wrapper": "372b62c9c7f9e70b3d8575b13dc5b959187761486ce81acae8cacd0df6f35f8b"
|
|
10
10
|
}
|
|
11
11
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.3.
|
|
2
|
+
"version": "0.3.1",
|
|
3
3
|
"platform": "darwin",
|
|
4
4
|
"arch": "x64",
|
|
5
|
-
"gitCommit": "
|
|
6
|
-
"builtAt": "2026-10-
|
|
5
|
+
"gitCommit": "100e480b2e58ee1e68fed4c1d34bc6db5b9f471f",
|
|
6
|
+
"builtAt": "2026-10-06T06:10:23.000Z",
|
|
7
7
|
"sha256": {
|
|
8
|
-
"pi-remote-helper": "
|
|
9
|
-
"pi-remote-launch-wrapper": "
|
|
8
|
+
"pi-remote-helper": "236d7bf79b775879ec873f2f24b6e8ba4201da31d0e2699602c8302f257e336e",
|
|
9
|
+
"pi-remote-launch-wrapper": "b3203f811753ab32ea92cad68fb4fed1cf3265355099bbcacff215d964524729"
|
|
10
10
|
}
|
|
11
11
|
}
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED