mindwire 0.1.27 → 0.1.29
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/dist/{chunk-QXHI4TMC.js → chunk-QPZMGVY7.js} +14 -6
- package/dist/chunk-QPZMGVY7.js.map +1 -0
- package/dist/cli.js +96 -89
- package/dist/cli.js.map +1 -1
- package/dist/computer/connection-flow.d.ts +13 -3
- package/dist/computer.d.ts +14 -1
- package/dist/{controller-7YV6O7GT.js → controller-MNMIJHH5.js} +3 -3
- package/dist/{controller-7YV6O7GT.js.map → controller-MNMIJHH5.js.map} +1 -1
- package/dist/index.cjs +11 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +11 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-QXHI4TMC.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { defaultStateDirectory, superviseComputer, ensureComputer, computerPairingURI, stopComputer, computerClient, SDK_VERSION, readJSON, writeJSON, currentProcessIdentity, processStateAlive, acquireProcessLock, computerPairingQRData } from './chunk-
|
|
2
|
+
import { defaultStateDirectory, superviseComputer, ensureComputer, computerPairingURI, stopComputer, computerClient, SDK_VERSION, readJSON, writeJSON, currentProcessIdentity, processStateAlive, acquireProcessLock, computerPairingQRData } from './chunk-QPZMGVY7.js';
|
|
3
3
|
import './chunk-T6TD76UA.js';
|
|
4
4
|
import { promisify, parseArgs } from 'util';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -7,16 +7,18 @@ import { realpathSync, mkdtempSync, chmodSync, writeFileSync, rmSync } from 'fs'
|
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { join } from 'path';
|
|
9
9
|
import { createHash } from 'crypto';
|
|
10
|
-
import { hostname, homedir, tmpdir } from 'os';
|
|
11
10
|
import { createInterface } from 'readline/promises';
|
|
12
11
|
import { setTimeout as setTimeout$1 } from 'timers/promises';
|
|
13
12
|
import { execFile, spawn } from 'child_process';
|
|
13
|
+
import { homedir, tmpdir } from 'os';
|
|
14
14
|
import * as fs from 'fs/promises';
|
|
15
15
|
|
|
16
16
|
var enterScreen = "\x1B[?1049h\x1B[?25l";
|
|
17
17
|
var leaveScreen = "\x1B[0m\x1B[?25h\x1B[?1049l";
|
|
18
18
|
var clearScreen = "\x1B[H\x1B[2J";
|
|
19
|
-
|
|
19
|
+
function scanInstruction(invitation) {
|
|
20
|
+
return "mode" in invitation && invitation.mode === "reconnect" ? "Workspaces \u2192 your computer \u2192 Reconnect Computer \u2192 Scan Connection Code" : "Mindwire \u2192 Add computer \u2192 Scan QR code";
|
|
21
|
+
}
|
|
20
22
|
async function createPairingQR(invitation) {
|
|
21
23
|
const QR = await import('qrcode');
|
|
22
24
|
const data = computerPairingQRData(invitation);
|
|
@@ -34,7 +36,7 @@ async function createPairingQR(invitation) {
|
|
|
34
36
|
lines.push("\x1B[30;107m" + line + "\x1B[0m");
|
|
35
37
|
}
|
|
36
38
|
const svg = await QR.toString(data, { ...options, type: "svg" });
|
|
37
|
-
return { lines, columns: Math.max(width, scanInstruction.length) + 1, rows: lines.length + 5, svg };
|
|
39
|
+
return { lines, columns: Math.max(width, scanInstruction(invitation).length) + 1, rows: lines.length + 5, svg };
|
|
38
40
|
}
|
|
39
41
|
function escapeHTML(value) {
|
|
40
42
|
return value.replace(/[&<>"']/g, (ch) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" })[ch]);
|
|
@@ -60,15 +62,15 @@ textarea{width:100%;margin-top:12px;padding:8px;color:inherit;background:#252528
|
|
|
60
62
|
<small>MINDWIRE</small><h1>${title}</h1><p>${escapeHTML(invitation.name)}</p>
|
|
61
63
|
<div class="code" id="code" role="img" aria-label="Mindwire connection QR code">${svg}</div>
|
|
62
64
|
<p id="expiry" data-expires="${escapeHTML(invitation.expiresAt)}" aria-live="off"></p>
|
|
63
|
-
<div class="steps"><p>In Mindwire, open <strong>Add computer</strong> and scan
|
|
64
|
-
<p>${reconnect ? "Your saved pairing and workspace stay the same. No new approval is needed." : "
|
|
65
|
+
<div class="steps"><p>${reconnect ? "In Mindwire, open your computer in <strong>Workspaces</strong>, then <strong>Reconnect Computer \u2192 Scan Connection Code</strong>." : "In Mindwire, open <strong>Add computer</strong> and scan."}</p>
|
|
66
|
+
<p>${reconnect ? "Your saved pairing and workspace stay the same. No new approval is needed." : "Saved keys reconnect automatically. Approve on this computer only if asked."}</p></div>
|
|
65
67
|
<button type="button" id="copy">Copy ${reconnect ? "reconnect" : "pairing"} link</button>
|
|
66
68
|
<textarea id="link" readonly hidden aria-label="Pairing link">${escapeHTML(computerPairingURI(invitation))}</textarea>
|
|
67
69
|
<footer>You can close this page after ${reconnect ? "reconnecting" : "pairing"}.</footer>
|
|
68
70
|
</main><script>
|
|
69
71
|
const expiry=document.getElementById('expiry'),code=document.getElementById('code'),copy=document.getElementById('copy'),link=document.getElementById('link');
|
|
70
72
|
function tick(){const seconds=Math.max(0,Math.ceil((Date.parse(expiry.dataset.expires)-Date.now())/1000));
|
|
71
|
-
if(!seconds){code.remove();copy.disabled=true;link.value='';link.hidden=true;expiry.textContent='Code expired. Run mindwire
|
|
73
|
+
if(!seconds){code.remove();copy.disabled=true;link.value='';link.hidden=true;expiry.textContent='Code expired. Run mindwire connect for a new code.';return;}
|
|
72
74
|
expiry.textContent='Expires in '+Math.floor(seconds/60)+':'+String(seconds%60).padStart(2,'0');}
|
|
73
75
|
tick();setInterval(tick,1000);
|
|
74
76
|
copy.addEventListener('click',async()=>{try{await navigator.clipboard.writeText(link.value);copy.textContent='Copied';}
|
|
@@ -93,16 +95,18 @@ async function openBrowser(url) {
|
|
|
93
95
|
}
|
|
94
96
|
async function showPairingInvitation(invitation, options = {}) {
|
|
95
97
|
const reconnect = "mode" in invitation && invitation.mode === "reconnect";
|
|
96
|
-
const
|
|
98
|
+
const instruction = scanInstruction(invitation);
|
|
99
|
+
const nextStep = reconnect ? "Scan with a saved phone." : "Approve on this computer only if asked.";
|
|
97
100
|
const waiting = reconnect ? "Your saved pairing stays the same." : "Waiting for your phone\u2026";
|
|
98
|
-
const command =
|
|
101
|
+
const command = "mindwire connect";
|
|
99
102
|
const output = options.output ?? process.stdout;
|
|
100
103
|
const environment = options.environment ?? process.env;
|
|
101
104
|
const mode = options.mode ?? "auto";
|
|
102
105
|
const interactive = !!output.isTTY && environment.TERM !== "dumb";
|
|
103
106
|
const linkOnly = mode === "none" || !interactive && mode !== "browser";
|
|
104
107
|
if (linkOnly) {
|
|
105
|
-
|
|
108
|
+
const destination = reconnect ? "Workspaces \u2192 your computer \u2192 Reconnect Computer" : "Add computer";
|
|
109
|
+
output.write(`Paste this link in Mindwire \u2192 ${destination} (expires in 5 minutes):
|
|
106
110
|
${computerPairingURI(invitation)}
|
|
107
111
|
|
|
108
112
|
${waiting}
|
|
@@ -121,10 +125,10 @@ ${waiting}
|
|
|
121
125
|
if (closed || !useScreen) return;
|
|
122
126
|
let lines;
|
|
123
127
|
if (fits()) {
|
|
124
|
-
lines = [
|
|
128
|
+
lines = [instruction, "", ...qr.lines, "", waiting];
|
|
125
129
|
} else {
|
|
126
130
|
const size = `Terminal QR needs ${qr.columns} columns \xD7 ${qr.rows} rows.`;
|
|
127
|
-
lines = browser === "opened" ? ["QR opened in your browser.",
|
|
131
|
+
lines = browser === "opened" ? ["QR opened in your browser.", instruction, nextStep] : browser === "opening" ? ["Opening a resizable QR in your browser\u2026", nextStep] : browser === "failed" ? ["Couldn't open a browser here.", size, "Enlarge this terminal, or run:", `${command} --no-qr`] : [size, "Enlarge this terminal, or use --qr browser."];
|
|
128
132
|
lines = lines.map((line) => line.slice(0, Math.max(0, (output.columns ?? 80) - 1))).slice(0, Math.max(0, (output.rows ?? 24) - 1));
|
|
129
133
|
}
|
|
130
134
|
output.write(clearScreen + lines.join("\r\n"));
|
|
@@ -149,7 +153,7 @@ ${waiting}
|
|
|
149
153
|
if (closed) return;
|
|
150
154
|
if (useScreen) draw();
|
|
151
155
|
else output.write(browser === "opened" ? `QR opened in your browser.
|
|
152
|
-
${
|
|
156
|
+
${instruction}
|
|
153
157
|
${nextStep}
|
|
154
158
|
` : `Open this local QR page in a browser:
|
|
155
159
|
${pageURL ?? `Page unavailable. Run ${command} --no-qr for a link.`}
|
|
@@ -414,22 +418,23 @@ function connectionAction(value) {
|
|
|
414
418
|
throw new Error("Use mindwire connect, mindwire connect resume, mindwire reconnect, or mindwire connect pair.");
|
|
415
419
|
}
|
|
416
420
|
async function chooseConnectionAction(options) {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
421
|
+
if (options.requested === "pair" || options.requested === "reconnect") return "pair";
|
|
422
|
+
return options.devices.some((device) => !device.revoked && device.connected) ? "resume" : "pair";
|
|
423
|
+
}
|
|
424
|
+
async function choosePairingDecision(options) {
|
|
425
|
+
const replacements = options.replacements.filter((device) => !device.revoked);
|
|
426
|
+
const prompt = replacements.length ? `
|
|
427
|
+
Previous approvals with this name:
|
|
428
|
+
${deviceSummary(replacements, true)}
|
|
429
|
+
|
|
430
|
+
Allow this phone? [r = replace these approvals, a = add a different phone, N = deny]: ` : "Allow this phone to access this workspace? [y/N] ";
|
|
426
431
|
for (; ; ) {
|
|
427
|
-
const answer = (await options.question(
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
if (
|
|
432
|
+
const answer = (await options.question(prompt)).trim().toLowerCase();
|
|
433
|
+
if (["", "n", "no"].includes(answer)) return { approve: false };
|
|
434
|
+
if (replacements.length) {
|
|
435
|
+
if (["r", "replace"].includes(answer)) return { approve: true, replaceDeviceIds: replacements.map((device) => device.id) };
|
|
436
|
+
if (["a", "add"].includes(answer)) return { approve: true };
|
|
437
|
+
} else if (["y", "yes"].includes(answer)) return { approve: true };
|
|
433
438
|
}
|
|
434
439
|
}
|
|
435
440
|
async function chooseStartupAction(options) {
|
|
@@ -446,24 +451,16 @@ async function chooseStartupAction(options) {
|
|
|
446
451
|
if (["n", "no"].includes(answer)) return false;
|
|
447
452
|
}
|
|
448
453
|
}
|
|
449
|
-
function
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
fingerprint: info.fingerprint,
|
|
457
|
-
name,
|
|
458
|
-
routes: info.routes,
|
|
459
|
-
expiresAt: new Date(now.getTime() + 5 * 6e4).toISOString()
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
function deviceSummary(devices) {
|
|
463
|
-
return devices.filter((device) => !device.revoked).sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id)).map((device) => {
|
|
464
|
-
const name = device.name.replace(/[\x00-\x1f\x7f-\x9f]/g, "");
|
|
454
|
+
function deviceSummary(devices, showKeys = false) {
|
|
455
|
+
const saved = devices.filter((device) => !device.revoked);
|
|
456
|
+
const names = /* @__PURE__ */ new Map();
|
|
457
|
+
const safeName2 = (device) => device.name.replace(/[\x00-\x1f\x7f-\x9f]/g, "");
|
|
458
|
+
for (const device of saved) names.set(safeName2(device), (names.get(safeName2(device)) ?? 0) + 1);
|
|
459
|
+
return saved.sort((a, b) => a.name.localeCompare(b.name) || a.id.localeCompare(b.id)).map((device) => {
|
|
460
|
+
const name = safeName2(device);
|
|
465
461
|
const status = device.connected === true ? "connected" : "paired";
|
|
466
|
-
|
|
462
|
+
const identity = showKeys || (names.get(name) ?? 0) > 1 ? ` \xB7 key ${device.id.slice(0, 8)}` : "";
|
|
463
|
+
return ` ${name} \xB7 ${status}${identity}`;
|
|
467
464
|
}).join("\n");
|
|
468
465
|
}
|
|
469
466
|
|
|
@@ -471,9 +468,8 @@ function deviceSummary(devices) {
|
|
|
471
468
|
var help = `Mindwire \u2014 connect this computer to your phone
|
|
472
469
|
|
|
473
470
|
npm install -g mindwire
|
|
474
|
-
mindwire connect
|
|
475
|
-
mindwire
|
|
476
|
-
mindwire reconnect Refresh a saved phone's address with a QR code
|
|
471
|
+
mindwire connect Connect your phone; saved keys reconnect automatically
|
|
472
|
+
mindwire reconnect Show a connection QR again (also repairs a missing pairing)
|
|
477
473
|
mindwire connect pair Pair another phone with this computer
|
|
478
474
|
mindwire connect --relay none --host laptop.tailnet Use your existing VPN
|
|
479
475
|
mindwire connect --relay none Direct SSH only (reachable network required)
|
|
@@ -502,6 +498,7 @@ Options:
|
|
|
502
498
|
--no-qr Print only the pairing link
|
|
503
499
|
--startup Enable automatic startup without a prompt
|
|
504
500
|
--no-startup Skip automatic startup setup
|
|
501
|
+
--replace-device DEVICE_ID With approve: replace a lost phone key (repeatable)
|
|
505
502
|
|
|
506
503
|
The default works across Wi-Fi and mobile networks. Mindwire privately downloads
|
|
507
504
|
a verified Cloudflare helper when needed. Relays carry encrypted SSH.
|
|
@@ -531,7 +528,8 @@ async function main(args = process.argv.slice(2)) {
|
|
|
531
528
|
version: { type: "string" },
|
|
532
529
|
force: { type: "boolean" },
|
|
533
530
|
startup: { type: "boolean" },
|
|
534
|
-
"no-startup": { type: "boolean" }
|
|
531
|
+
"no-startup": { type: "boolean" },
|
|
532
|
+
"replace-device": { type: "string", multiple: true }
|
|
535
533
|
} });
|
|
536
534
|
const command = positionals[0] ?? "help";
|
|
537
535
|
if (values.help || command === "help") {
|
|
@@ -600,7 +598,7 @@ async function main(args = process.argv.slice(2)) {
|
|
|
600
598
|
const devices = await client2.computer.devices();
|
|
601
599
|
const saved = devices.filter((device) => !device.revoked);
|
|
602
600
|
if (saved.length) emit("saved_devices", { devices: saved }, `
|
|
603
|
-
Saved
|
|
601
|
+
Saved approvals on this computer
|
|
604
602
|
${deviceSummary(saved)}`);
|
|
605
603
|
const question = !values.json && process.stdin.isTTY ? async (prompt) => {
|
|
606
604
|
const input = createInterface({ input: process.stdin, output: process.stderr });
|
|
@@ -610,13 +608,13 @@ ${deviceSummary(saved)}`);
|
|
|
610
608
|
input.close();
|
|
611
609
|
}
|
|
612
610
|
} : void 0;
|
|
613
|
-
const action = await chooseConnectionAction({ requested: requestedAction, devices
|
|
611
|
+
const action = await chooseConnectionAction({ requested: requestedAction, devices });
|
|
614
612
|
const startupPreference = await startupStatus(directory);
|
|
615
613
|
const startupAction = await chooseStartupAction({
|
|
616
614
|
state: startupPreference,
|
|
617
615
|
startup: values.startup,
|
|
618
616
|
noStartup: values["no-startup"],
|
|
619
|
-
question
|
|
617
|
+
question: action === "pair" && saved.length === 0 ? question : void 0
|
|
620
618
|
});
|
|
621
619
|
if (startupAction !== void 0) {
|
|
622
620
|
try {
|
|
@@ -629,29 +627,12 @@ ${deviceSummary(saved)}`);
|
|
|
629
627
|
emit("startup", startupPreference, startupPreference.enabled ? "Automatic startup is on. Change it with mindwire startup disable." : "Automatic startup is off. Enable it with mindwire startup enable.");
|
|
630
628
|
}
|
|
631
629
|
if (action === "resume") {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
if (action === "reconnect") {
|
|
639
|
-
const code = reconnectCode(await client2.computer.info(), hostname());
|
|
640
|
-
emit("reconnect_code", { code, uri: computerPairingURI(code) });
|
|
641
|
-
if (values.json) return;
|
|
642
|
-
const display2 = await showPairingInvitation(code, {
|
|
643
|
-
mode: values["no-qr"] ? "none" : values.qr ?? "auto"
|
|
644
|
-
});
|
|
645
|
-
try {
|
|
646
|
-
if (question) await question("\nScan with your saved phone, then press Enter to close this code. ");
|
|
647
|
-
else if (values.qr === "browser") {
|
|
648
|
-
emit("waiting", {}, "This code stays open until it expires. Press Ctrl+C to close it; Mindwire keeps running.");
|
|
649
|
-
await setTimeout$1(Math.max(0, Date.parse(code.expiresAt) - Date.now()));
|
|
650
|
-
}
|
|
651
|
-
} finally {
|
|
652
|
-
display2.close();
|
|
653
|
-
}
|
|
654
|
-
emit("resumed", { computerId: info.computerId }, "Saved pairing kept. Mindwire continues running in the background.");
|
|
630
|
+
const connected = saved.filter((device) => device.connected);
|
|
631
|
+
emit("connected", { computerId: info.computerId, devices: connected }, `
|
|
632
|
+
Connected:
|
|
633
|
+
${deviceSummary(connected)}
|
|
634
|
+
Mindwire continues running in the background.`);
|
|
635
|
+
emit("connect_hint", {}, "To scan again or add a phone, run mindwire reconnect.");
|
|
655
636
|
return;
|
|
656
637
|
}
|
|
657
638
|
const invitation = await client2.computer.invite((await client2.computer.info()).routes);
|
|
@@ -662,12 +643,31 @@ ${deviceSummary(saved)}`);
|
|
|
662
643
|
});
|
|
663
644
|
try {
|
|
664
645
|
let shownRequest;
|
|
646
|
+
let authorized = false;
|
|
665
647
|
while (Date.now() < Date.parse(invitation.expiresAt)) {
|
|
666
648
|
const pairing = await client2.computer.pairing(invitation.pairingId);
|
|
649
|
+
if (pairing.status === "waiting" && requestedAction !== "pair" && requestedAction !== "reconnect") {
|
|
650
|
+
const connected = (await client2.computer.devices()).filter((device) => !device.revoked && device.connected);
|
|
651
|
+
if (connected.length && ((info.pairingVersion ?? 0) < 2 || (await client2.computer.closeUnusedPairing(invitation.pairingId)).cancelled)) {
|
|
652
|
+
display?.close();
|
|
653
|
+
emit("connected", { computerId: info.computerId, devices: connected }, `Connected:
|
|
654
|
+
${deviceSummary(connected)}
|
|
655
|
+
Mindwire continues running in the background.`);
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
667
659
|
if (pairing.status === "approved") {
|
|
668
660
|
display?.close();
|
|
669
|
-
|
|
670
|
-
|
|
661
|
+
if (pairing.completed) {
|
|
662
|
+
emit("paired", { computerId: info.computerId, completed: true }, "Phone connected and saved. You can close this terminal; Mindwire keeps running.");
|
|
663
|
+
return;
|
|
664
|
+
}
|
|
665
|
+
if (!authorized) {
|
|
666
|
+
authorized = true;
|
|
667
|
+
emit("authorized", {}, "Phone authorized. Waiting for it to save the connection\u2026");
|
|
668
|
+
}
|
|
669
|
+
await setTimeout$1(750);
|
|
670
|
+
continue;
|
|
671
671
|
}
|
|
672
672
|
if (pairing.status === "rejected") {
|
|
673
673
|
display?.close();
|
|
@@ -679,14 +679,16 @@ ${deviceSummary(saved)}`);
|
|
|
679
679
|
shownRequest = pairing.request.id;
|
|
680
680
|
const key = Buffer.from(pairing.request.publicKey.split(" ")[1] ?? "", "base64");
|
|
681
681
|
const fingerprint = "SHA256:" + createHash("sha256").update(key).digest("base64").replace(/=+$/, "");
|
|
682
|
+
const deviceId = createHash("sha256").update(key).digest("base64url");
|
|
683
|
+
const replacements = (info.pairingVersion ?? 0) >= 2 ? (await client2.computer.devices()).filter((device) => !device.revoked && device.id !== deviceId && device.name === pairing.request.name) : [];
|
|
682
684
|
emit(
|
|
683
685
|
"approval_required",
|
|
684
|
-
{ pairingId: invitation.pairingId, request: pairing.request, fingerprint },
|
|
686
|
+
{ pairingId: invitation.pairingId, request: pairing.request, fingerprint, replacements },
|
|
685
687
|
`
|
|
686
688
|
${safeName(pairing.request.name)} wants to connect.
|
|
687
689
|
Device key: ${fingerprint}`
|
|
688
690
|
);
|
|
689
|
-
if (!
|
|
691
|
+
if (!question) {
|
|
690
692
|
emit(
|
|
691
693
|
"approval_command",
|
|
692
694
|
{ command: `mindwire approve ${invitation.pairingId} ${pairing.request.id}` },
|
|
@@ -694,18 +696,18 @@ Device key: ${fingerprint}`
|
|
|
694
696
|
mindwire approve ${invitation.pairingId} ${pairing.request.id}`
|
|
695
697
|
);
|
|
696
698
|
} else {
|
|
697
|
-
const
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
699
|
+
const decision = await choosePairingDecision({ replacements, question });
|
|
700
|
+
await client2.computer.decide(
|
|
701
|
+
invitation.pairingId,
|
|
702
|
+
pairing.request.id,
|
|
703
|
+
decision.approve,
|
|
704
|
+
decision.replaceDeviceIds ? { replaceDeviceIds: decision.replaceDeviceIds } : {}
|
|
705
|
+
);
|
|
704
706
|
}
|
|
705
707
|
}
|
|
706
708
|
await setTimeout$1(750);
|
|
707
709
|
}
|
|
708
|
-
throw new Error("
|
|
710
|
+
throw new Error(authorized ? "The phone was approved but did not finish saving. Run mindwire connect and scan again; its saved key will be reused." : "Connection code expired. Run mindwire connect to show a new QR code.");
|
|
709
711
|
} finally {
|
|
710
712
|
display?.close();
|
|
711
713
|
}
|
|
@@ -749,8 +751,13 @@ ${controller.error}` : ""}`
|
|
|
749
751
|
case "approve":
|
|
750
752
|
case "reject": {
|
|
751
753
|
if (!positionals[1] || !positionals[2]) throw new Error(`Use mindwire ${command} PAIRING_ID REQUEST_ID.`);
|
|
752
|
-
await client.computer.decide(
|
|
753
|
-
|
|
754
|
+
await client.computer.decide(
|
|
755
|
+
positionals[1],
|
|
756
|
+
positionals[2],
|
|
757
|
+
command === "approve",
|
|
758
|
+
values["replace-device"] ? { replaceDeviceIds: values["replace-device"] } : {}
|
|
759
|
+
);
|
|
760
|
+
emit(command, {}, command === "approve" ? "Phone approved. Waiting for it to save the connection." : "Phone declined.");
|
|
754
761
|
break;
|
|
755
762
|
}
|
|
756
763
|
case "update": {
|