mars-ram 0.0.0-stage → 0.1.3
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/README.md +25 -2
- package/archive/mars-ram-0.1.3.tar.gz +0 -0
- package/bin/mars-ram.mjs +95 -0
- package/package.json +21 -4
package/README.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# mars-ram 0.1.3
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The computer side of mars-ram: the command that pairs your phone with this computer, the Pi session bridge and the private-link server. Linux, macOS and Windows; Node.js 24 or newer.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pnpm add -g mars-ram # recommended
|
|
7
|
+
npm i -g mars-ram # or
|
|
8
|
+
bun add -g mars-ram # or
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Then:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
mars-ram install
|
|
15
|
+
mars-ram pair
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
`mars-ram install` copies everything to `~/.mars-ram` in your user account (no administrator rights) and installs the bridge into each Pi you choose. `mars-ram doctor` checks the setup, `mars-ram uninstall` removes it (then `pnpm remove -g mars-ram` removes the package). To update: `pnpm add -g mars-ram`, then `mars-ram install`; if you installed earlier with the curl script and `mars-ram install` still runs the old version, run `mars-ram uninstall` first.
|
|
19
|
+
|
|
20
|
+
The package has no install scripts and no dependencies. It carries the release archive `mars-ram-0.1.3.tar.gz` (SHA-256 `7f0bf65fad1a5c2398c8d8bb7047c7c7de91867d81671ef4771d34f78809836e`, the same file as the GitHub release) and a launcher that checks that SHA-256, unpacks the archive into a private temporary folder and runs it, because Node does not run TypeScript from `node_modules`. After `mars-ram install`, the launcher runs the installed copy directly when it is this same version.
|
|
21
|
+
|
|
22
|
+
Install guide: https://marssall.github.io/mars-ram/install
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
**Español.** Instalá con `pnpm add -g mars-ram` (recomendado) o `npm i -g mars-ram`, después ejecutá `mars-ram install` y `mars-ram pair`. Requiere Node.js 24 o más nuevo. Guía: https://marssall.github.io/mars-ram/install
|
|
Binary file
|
package/bin/mars-ram.mjs
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// mars-ram npm launcher. Node refuses to strip TypeScript types under node_modules, so this package carries the
|
|
3
|
+
// release archive and runs it from a private temporary folder, as install.sh does. Node built-ins only; rendered by
|
|
4
|
+
// host/cli/scripts/build-release.ts, which writes the version, the archive SHA-256 and the CLI fingerprint below.
|
|
5
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
6
|
+
import { createHash } from 'node:crypto';
|
|
7
|
+
import { lstatSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
8
|
+
import { constants, homedir, tmpdir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
|
|
11
|
+
const VERSION = '0.1.3';
|
|
12
|
+
const ARCHIVE_SHA256 = '7f0bf65fad1a5c2398c8d8bb7047c7c7de91867d81671ef4771d34f78809836e';
|
|
13
|
+
const CLI_FINGERPRINT = 'f53d63e493b1f2d1a7850694b2b41c112621a7840088ebc73d55fe99a31fd269';
|
|
14
|
+
|
|
15
|
+
// Same locale rule as the CLI (host/cli/src/adapters/terminal.ts); an empty variable counts as unset.
|
|
16
|
+
const spanish = (process.env.LC_ALL || process.env.LC_MESSAGES || process.env.LANG || Intl.DateTimeFormat().resolvedOptions().locale).toLowerCase().startsWith('es');
|
|
17
|
+
const say = (en, es) => spanish ? es : en;
|
|
18
|
+
function fail(message) {
|
|
19
|
+
process.stderr.write(`${message}\n`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const packageRoot = join(import.meta.dirname, '..');
|
|
25
|
+
|
|
26
|
+
// The copy `mars-ram install` wrote runs directly when it is this package's CLI; install and uninstall always run
|
|
27
|
+
// from the package, so they never replace or remove the code that is running them.
|
|
28
|
+
function installedMain() {
|
|
29
|
+
if (args[0] === 'install' || args[0] === 'uninstall') return undefined;
|
|
30
|
+
const cli = join(homedir(), '.mars-ram', 'cli');
|
|
31
|
+
try {
|
|
32
|
+
if (readFileSync(join(cli, 'fingerprint.sha256'), 'utf8').trim() !== CLI_FINGERPRINT) return undefined;
|
|
33
|
+
const main = join(cli, 'src', 'main.ts'), stat = lstatSync(main);
|
|
34
|
+
return stat.isFile() && !stat.isSymbolicLink() ? main : undefined;
|
|
35
|
+
} catch { return undefined; }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Checks the embedded archive against the SHA-256 pinned at build time, then unpacks the checked bytes (not the file
|
|
39
|
+
// again) into a new folder only this user can read.
|
|
40
|
+
function extract() {
|
|
41
|
+
const name = `mars-ram-${VERSION}`;
|
|
42
|
+
const bytes = readFileSync(join(packageRoot, 'archive', `${name}.tar.gz`));
|
|
43
|
+
const actual = createHash('sha256').update(bytes).digest('hex');
|
|
44
|
+
if (actual !== ARCHIVE_SHA256) fail(say(
|
|
45
|
+
`The mars-ram package is damaged: its archive does not match the expected SHA-256.\nExpected: ${ARCHIVE_SHA256}\nActual: ${actual}\nNothing was run. Reinstall it: pnpm add -g mars-ram (or npm i -g mars-ram).`,
|
|
46
|
+
`El paquete mars-ram está dañado: su archivo no coincide con el SHA-256 esperado.\nEsperado: ${ARCHIVE_SHA256}\nObtenido: ${actual}\nNo se ejecutó nada. Instalalo de nuevo: pnpm add -g mars-ram (o npm i -g mars-ram).`));
|
|
47
|
+
const dir = mkdtempSync(join(tmpdir(), 'mars-ram-'));
|
|
48
|
+
try {
|
|
49
|
+
writeFileSync(join(dir, 'archive.tar.gz'), bytes, { mode: 0o600, flag: 'wx' });
|
|
50
|
+
// Windows 10+ ships bsdtar as System32\tar.exe; name it so an earlier tar on PATH is never picked.
|
|
51
|
+
const tar = process.platform === 'win32' ? join(process.env.SystemRoot ?? 'C:\\Windows', 'System32', 'tar.exe') : 'tar';
|
|
52
|
+
// Relative names with cwd: GNU tar would read "C:\..." as a remote host.
|
|
53
|
+
execFileSync(tar, ['-xzf', 'archive.tar.gz'], { cwd: dir, stdio: ['ignore', 'ignore', 'pipe'], shell: false, windowsHide: true });
|
|
54
|
+
rmSync(join(dir, 'archive.tar.gz'));
|
|
55
|
+
} catch (error) {
|
|
56
|
+
rmSync(dir, { recursive: true, force: true });
|
|
57
|
+
fail(say(`mars-ram could not unpack its files: ${error.message}`, `mars-ram no pudo descomprimir sus archivos: ${error.message}`));
|
|
58
|
+
}
|
|
59
|
+
return { main: join(dir, name, 'cli', 'src', 'main.ts'), dir };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Signal handlers come first, before the archive is unpacked: a SIGTERM or SIGHUP that arrives during startup then waits
|
|
63
|
+
// for the synchronous unpacking, reaches the CLI as soon as it starts, and the temporary copy is still removed. Only
|
|
64
|
+
// SIGKILL leaves it behind. Ctrl+C reaches the whole process group, so the CLI gets it directly and decides; this
|
|
65
|
+
// process only waits. Signals sent to this process alone are passed on.
|
|
66
|
+
let child, dir;
|
|
67
|
+
const cleanup = () => { if (dir) rmSync(dir, { recursive: true, force: true }); };
|
|
68
|
+
const forward = signal => {
|
|
69
|
+
if (child) child.kill(signal);
|
|
70
|
+
else { cleanup(); process.exit(128 + (constants.signals[signal] ?? 0)); }
|
|
71
|
+
};
|
|
72
|
+
const handlers = { SIGINT: () => {}, SIGTERM: forward, SIGHUP: forward };
|
|
73
|
+
for (const [signal, handler] of Object.entries(handlers)) process.on(signal, handler);
|
|
74
|
+
|
|
75
|
+
const installed = installedMain();
|
|
76
|
+
let main = installed;
|
|
77
|
+
if (!installed) ({ main, dir } = extract());
|
|
78
|
+
|
|
79
|
+
// MARS_RAM_PACKAGE_BIN tells `mars-ram install` that this package's bin is the command, so it writes no launcher of
|
|
80
|
+
// its own (one earlier on PATH would keep running the old version).
|
|
81
|
+
child = spawn(process.execPath, ['--disable-warning=ExperimentalWarning', main, ...args], { stdio: 'inherit', shell: false, env: { ...process.env, MARS_RAM_PACKAGE_BIN: import.meta.filename } });
|
|
82
|
+
child.on('error', error => {
|
|
83
|
+
cleanup();
|
|
84
|
+
fail(say(`mars-ram could not start Node: ${error.message}`, `mars-ram no pudo iniciar Node: ${error.message}`));
|
|
85
|
+
});
|
|
86
|
+
child.on('exit', (code, signal) => {
|
|
87
|
+
cleanup();
|
|
88
|
+
for (const [name, handler] of Object.entries(handlers)) process.off(name, handler);
|
|
89
|
+
if (signal) {
|
|
90
|
+
// End the same way, so a calling shell sees the signal.
|
|
91
|
+
process.kill(process.pid, signal);
|
|
92
|
+
process.exit(128 + (constants.signals[signal] ?? 0));
|
|
93
|
+
}
|
|
94
|
+
process.exit(code ?? 1);
|
|
95
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mars-ram",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.3",
|
|
4
|
+
"description": "Computer side of mars-ram: pairs your phone with this computer and installs the Pi session bridge and private-link server.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mars-ram": "bin/mars-ram.mjs"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=24"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"archive",
|
|
15
|
+
"bin",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/MarsSall/mars-ram.git"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://marssall.github.io/mars-ram/install"
|
|
23
|
+
}
|