@inoku/lepan 0.7.66 → 0.7.67

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 CHANGED
@@ -86,7 +86,7 @@ The Linux/macOS legacy browser-owner setup uses the built-in AV1 registration en
86
86
 
87
87
  LifeDrive requires Leither V0.24.11 or newer. Linux/macOS browser-owner setup creates a separate Ed25519 `sodiumv2` identity for the primary browser. Windows prints a private ten-minute invitation for the first paired phone; later users and devices are managed from a paired device.
88
88
 
89
- After successful npm setup, the installer saves a private `lepan-pairing-<id>.png` and prints its full path. It also displays the QR code when it fits the terminal's width and height. In the iPhone or Android app, open **Settings → Set up users → Scan QR code** and scan the terminal or the saved image. A private `.json` invitation is saved alongside it for apps without a setup scanner: transfer that file to the phone and use **Choose identity file**. These files are saved in the Leither root on Linux/macOS and its private `.lifedrive-household` directory on Windows. Household invitations expire ten minutes after creation; legacy identity codes contain a device private key, so keep them private and delete the transfer copies after pairing. Legacy `--add-device` and `--upgrade` also produce a code when an identity is available; household upgrades preserve existing pairings without issuing new invitations.
89
+ After successful npm setup, the installer displays the QR code at the end of its output whenever the terminal is wide enough. If the whole code cannot fit on screen, it automatically opens the full-size QR image in the computer's image viewer. In the iPhone or Android app, open **Settings → Set up users → Scan QR code** and scan the displayed code. A private `lepan-pairing-<id>.png` is also saved, with its path printed as a fallback for remote sessions or computers without an image viewer. A private `.json` invitation is saved alongside it for apps without a setup scanner: transfer that file to the phone and use **Choose identity file**. These files are saved in the Leither root on Linux/macOS and its private `.lifedrive-household` directory on Windows. Household invitations expire ten minutes after creation; legacy identity codes contain a device private key, so keep them private and delete the transfer copies after pairing. Legacy `--add-device` and `--upgrade` also produce a code when an identity is available; household upgrades preserve existing pairings without issuing new invitations.
90
90
 
91
91
  ### Renew an expired first-phone invitation
92
92
 
package/USER_MANUAL.md CHANGED
@@ -142,8 +142,7 @@ This keeps what step 2.1 installed and adds users and phones:
142
142
 
143
143
  1. Creates LifeDrive's private configuration in `<Leither root>/.lifedrive-household/`.
144
144
  2. Installs and starts the identity service: `lifedrive-identity` through systemd on Linux, `uk.inoku.lifedrive-identity` through launchd on macOS, or `LifeDrive Identity` through Task Scheduler on Windows. Leither itself is not restarted and must be running separately.
145
- 3. Prints a **setup invitation**: a block of text, followed by
146
- *"Keep the invitation above private. It expires in ten minutes."*
145
+ 3. Displays a **setup invitation** as a QR code. If the terminal is too small, the full-size QR image opens automatically on this computer. The invitation expires in ten minutes.
147
146
 
148
147
  The setup invitation is what makes a phone the first user of this node. Treat it
149
148
  like a key: do not post it, email it to others, or paste it anywhere public.
@@ -152,7 +151,7 @@ like a key: do not post it, email it to others, or paste it anywhere public.
152
151
 
153
152
  Within ten minutes of the invitation being printed:
154
153
 
155
- 1. Keep the installer’s final QR code visible, or open the saved `lepan-pairing-<id>.png` using the path it prints. If you used the standalone shell installer, copy the whole invitation block instead.
154
+ 1. Scan the installer’s final QR code or the QR image that opens automatically. The saved image path is a fallback for remote sessions or computers without an image viewer. If you used the standalone shell installer, copy the whole invitation block instead.
156
155
  2. Open LifeDrive on the phone. The **Set up your LifeDrive** screen opens by itself (or open **Settings → Set up users**).
157
156
  3. Enter **Your name** and a name for this device.
158
157
  4. Tap **Scan QR code** and point the phone at the terminal or saved image. You can also use **Paste node identity** or **Choose identity file**.
@@ -168,7 +167,7 @@ empty page, or **Settings → Set up users**, opens it again.
168
167
 
169
168
  | Situation | What to do |
170
169
  |---|---|
171
- | The invitation expired before you pasted it | On the node, stop the identity service (`sudo systemctl stop lifedrive-identity` on Linux, or `sudo launchctl bootout system/uk.inoku.lifedrive-identity` on macOS) and run the command from 2.2 again for a fresh invitation. |
170
+ | The invitation expired before you pasted it | On the node, run `npx --yes @inoku/lepan@latest --household` again for a fresh QR code. Setup renews an unclaimed invitation and preserves the existing identity; no manual service commands are needed. |
172
171
  | You pasted it, but the app lost its connection or was closed | Open the app on **the same phone** and paste **the same invitation** again. A claim that has started can finish after the ten minutes have passed. Do not delete the app or ask for a new invitation: that would abandon the phone's pending key. |
173
172
  | Setup says the node already has users | The node has been claimed. Add further devices from **My devices** (section 4), not with a new setup invitation. |
174
173
 
package/bin/lifedrive.js CHANGED
@@ -12,6 +12,31 @@ const distributionDirectory = path.resolve(__dirname, "..", "dist");
12
12
  const bundlePath = path.join(distributionDirectory, "lifedrive-bundle.tar.gz");
13
13
  const checksumPath = `${bundlePath}.sha256`;
14
14
 
15
+ function openPairingImage(imagePath) {
16
+ // A remote server must not open a window in another user's desktop session.
17
+ if (process.env.SSH_CONNECTION || process.env.SSH_TTY) return false;
18
+ let command;
19
+ let args;
20
+ if (process.platform === "darwin") {
21
+ command = "/usr/bin/open";
22
+ args = [imagePath];
23
+ } else if (process.platform === "win32") {
24
+ command = "powershell.exe";
25
+ args = ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command",
26
+ "Start-Process -FilePath $env:LEPAN_PAIRING_IMAGE -ErrorAction Stop"];
27
+ } else if (process.platform === "linux" && (process.env.DISPLAY || process.env.WAYLAND_DISPLAY)) {
28
+ command = "xdg-open";
29
+ args = [imagePath];
30
+ } else {
31
+ return false;
32
+ }
33
+ const result = spawnSync(command, args, {
34
+ stdio: "ignore", timeout: 5000,
35
+ env: { ...process.env, LEPAN_PAIRING_IMAGE: imagePath },
36
+ });
37
+ return !result.error && result.status === 0;
38
+ }
39
+
15
40
  async function showPairingCode(resultPath) {
16
41
  if (!fs.existsSync(resultPath)) return;
17
42
  // The child writes this only after setup succeeds. Never scrape its output:
@@ -64,17 +89,27 @@ async function showPairingCode(resultPath) {
64
89
  process.stderr.write(renewalHint);
65
90
  return;
66
91
  }
67
- process.stdout.write("\nNext: pair your phone\n\n");
68
- process.stdout.write(" 1. Open LePan on your iPhone or Android phone.\n");
69
- process.stdout.write(" 2. Go to Settings > Set up users > Scan QR code.\n");
70
- // Small terminal codes use half-height blocks. If the terminal would wrap,
71
- // or scroll the instructions out of view, use the full-resolution PNG.
92
+ // Never hide a terminal code just because the window is short. Open the PNG
93
+ // automatically when the whole code cannot be visible at once, and put the
94
+ // terminal code last so subsequent instructions cannot scroll it away.
72
95
  const width = modules.size + options.margin * 2;
73
96
  const height = Math.ceil(width / 2);
74
- const fitsTerminal = process.stdout.isTTY && process.stdout.columns > width &&
75
- process.stdout.rows >= height + 26;
76
- if (fitsTerminal) {
77
- process.stdout.write(" 3. Scan the code below.\n\n");
97
+ const fitsWidth = process.stdout.isTTY && process.stdout.columns > width;
98
+ const fitsScreen = fitsWidth && process.stdout.rows >= height + 3;
99
+ const imageOpened = !fitsScreen && openPairingImage(imagePath);
100
+ process.stdout.write("\nPair your phone\n\n");
101
+ process.stdout.write("Open LePan > Settings > Set up users > Scan QR code.\n");
102
+ process.stdout.write(imageOpened
103
+ ? "The QR image has opened automatically. Scan it with your phone.\n"
104
+ : fitsWidth ? "Scan the QR code below with your phone.\n"
105
+ : "This terminal is too narrow for the QR code and no image viewer could be opened. Open the saved image below.\n");
106
+ process.stdout.write(`${privacyNote}\n`);
107
+ process.stdout.write(`\nSaved QR image: ${imagePath}\n`);
108
+ process.stdout.write(`Pairing file (Choose identity file): ${identityPath}\n`);
109
+ process.stdout.write("Keep this computer on and connected while using LePan.\n");
110
+ process.stdout.write(renewalHint);
111
+ if (fitsWidth) {
112
+ process.stdout.write("\n");
78
113
  // Explicit colors and a four-module quiet zone work on light/dark themes.
79
114
  const dark = (x, y) => x >= 0 && y >= 0 && x < modules.size && y < modules.size && modules.get(y, x);
80
115
  let terminal = "";
@@ -86,16 +121,7 @@ async function showPairingCode(resultPath) {
86
121
  terminal += "\x1b[0m\n";
87
122
  }
88
123
  process.stdout.write(terminal);
89
- } else {
90
- process.stdout.write(" 3. Open the saved QR image on this computer and scan it.\n");
91
124
  }
92
- process.stdout.write(`\nQR image:\n ${imagePath}\n\n${privacyNote}\n`);
93
- process.stdout.write("\nNo Scan QR code button? Transfer this pairing file to your phone:\n");
94
- process.stdout.write(` ${identityPath}\n`);
95
- process.stdout.write("Then open Settings > Set up users > Choose identity file.\n");
96
- process.stdout.write("Keep the pairing file private; delete the transfer copy after import.\n");
97
- process.stdout.write("Keep this computer on and connected while using LePan.\n");
98
- process.stdout.write(renewalHint);
99
125
  }
100
126
 
101
127
  async function runInstaller(command, args) {
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: package/dist/lifedrive-bundle.tar.gz
3
- size: 44139710 bytes
4
- sha256: 134de0bb85330eb3192e837e5054074969a80cbb4eaa1ee0b7870e55b9a3b310
3
+ size: 44139682 bytes
4
+ sha256: 2173717546eb881f72dce0fdd7a5a6727bfc5286b4c23f948528b9d8f1a2fde8
@@ -1 +1 @@
1
- 134de0bb85330eb3192e837e5054074969a80cbb4eaa1ee0b7870e55b9a3b310 lifedrive-bundle.tar.gz
1
+ 2173717546eb881f72dce0fdd7a5a6727bfc5286b4c23f948528b9d8f1a2fde8 lifedrive-bundle.tar.gz
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inoku/lepan",
3
- "version": "0.7.66",
3
+ "version": "0.7.67",
4
4
  "description": "Install LePan and its Leither runtime on Linux, macOS, or Windows",
5
5
  "os": [
6
6
  "linux",