use-pounce 0.1.0 → 0.2.0
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/pounce.mjs +43 -20
- package/dist/launcher.mjs +1 -1
- package/package.json +1 -1
package/bin/pounce.mjs
CHANGED
|
@@ -204,7 +204,7 @@ async function ensureTunnelBinary(opts) {
|
|
|
204
204
|
}
|
|
205
205
|
if (!assetUrl) return { skipped: `no ${wanted} on any tunnel-v* release yet` };
|
|
206
206
|
}
|
|
207
|
-
process.stdout.write(dim(` downloading
|
|
207
|
+
process.stdout.write(dim(` downloading the remote-access component (${triple})…\n`));
|
|
208
208
|
const res = await fetch(assetUrl, { signal: AbortSignal.timeout(120_000) });
|
|
209
209
|
if (!res.ok) throw new Error(`download -> ${res.status}`);
|
|
210
210
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
@@ -300,12 +300,18 @@ async function waitForPhone(port) {
|
|
|
300
300
|
}
|
|
301
301
|
|
|
302
302
|
// --- commands -----------------------------------------------------------------
|
|
303
|
+
function printPairing(pairUrl, token, tunnel) {
|
|
304
|
+
const link = deepLink({ pairUrl, token, tunnel });
|
|
305
|
+
console.log(
|
|
306
|
+
`\n ${bold("Scan with the Pounce app")} ${dim("(Settings → Scan QR)")} ${bold("or your camera:")}\n`,
|
|
307
|
+
);
|
|
308
|
+
qrcode.generate(link, { small: true });
|
|
309
|
+
console.log(`\n ${dim("or open on the phone:")}\n ${dim(link)}\n`);
|
|
310
|
+
}
|
|
311
|
+
|
|
303
312
|
async function cmdUp(opts, { wait }) {
|
|
304
313
|
console.log(`\n${bold("🐾 Pounce")} ${dim(`v${PKG.version}`)} — pair your phone\n`);
|
|
305
314
|
|
|
306
|
-
// Tunnel binary first: a bridge spawned after it exists picks it up itself.
|
|
307
|
-
const tunnelState = await ensureTunnelBinary(opts);
|
|
308
|
-
|
|
309
315
|
let reused = false;
|
|
310
316
|
let pid = null;
|
|
311
317
|
if (await bridgeAlive(opts.port)) {
|
|
@@ -328,28 +334,45 @@ async function cmdUp(opts, { wait }) {
|
|
|
328
334
|
` ${dim("bridge")} ${pairUrl} ${dim(reused ? "(already running)" : `(started · pid ${pid} · logs: pounce logs)`)}`,
|
|
329
335
|
);
|
|
330
336
|
|
|
331
|
-
|
|
332
|
-
|
|
337
|
+
// ONE code, shown as fast as possible. The remote identity is stable across
|
|
338
|
+
// restarts, so on any machine that has run before /ui already carries it and
|
|
339
|
+
// the QR is remote-capable instantly. Only a machine's very first run holds
|
|
340
|
+
// the QR briefly while remote access is minted — never a second code; if
|
|
341
|
+
// remote isn't ready in time, the LAN code still upgrades the phone to
|
|
342
|
+
// remote automatically after it pairs (the app captures /v1/pair on connect).
|
|
343
|
+
let tunnel = ui.tunnel?.nodeId ? ui.tunnel : null;
|
|
344
|
+
let remoteNote = null;
|
|
345
|
+
if (!tunnel && !opts.lan) {
|
|
346
|
+
console.log(` ${dim("Setting up remote access… (first run only — takes a few seconds)")}`);
|
|
347
|
+
const state = await ensureTunnelBinary(opts);
|
|
348
|
+
if (state.skipped) {
|
|
349
|
+
remoteNote = `${yellow("!")} Pairs over your Wi-Fi for now ${dim(`(remote access unavailable: ${state.skipped})`)}`;
|
|
350
|
+
} else {
|
|
351
|
+
tunnel = (await waitForTunnel(opts.port, token)).tunnel;
|
|
352
|
+
if (!tunnel) {
|
|
353
|
+
remoteNote = `${yellow("!")} Pairs over your Wi-Fi for now — remote access is still warming up and will switch on automatically after you pair`;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
printPairing(pairUrl, token, tunnel);
|
|
358
|
+
|
|
359
|
+
if (opts.lan) {
|
|
333
360
|
console.log(
|
|
334
|
-
` ${dim("
|
|
361
|
+
` ${dim("Wi-Fi-only mode (--lan): scan while on the same network as this machine")}`,
|
|
335
362
|
);
|
|
336
|
-
} else {
|
|
337
|
-
|
|
338
|
-
|
|
363
|
+
} else if (tunnel) {
|
|
364
|
+
// Confirm the remote link quietly; the code on screen never changes (the
|
|
365
|
+
// identity is stable) — this only decides which status line to show.
|
|
366
|
+
const r = await waitForTunnel(opts.port, token, { timeoutMs: 12_000 });
|
|
339
367
|
console.log(
|
|
340
|
-
tunnel
|
|
341
|
-
? ` ${
|
|
342
|
-
: ` ${
|
|
368
|
+
r.tunnel
|
|
369
|
+
? ` ${green("✓")} Works from anywhere — Wi-Fi at home, an encrypted tunnel everywhere else`
|
|
370
|
+
: ` ${yellow("!")} Pairs over your Wi-Fi for now — the remote link is reconnecting in the background`,
|
|
343
371
|
);
|
|
372
|
+
} else if (remoteNote) {
|
|
373
|
+
console.log(` ${remoteNote}`);
|
|
344
374
|
}
|
|
345
375
|
|
|
346
|
-
const link = deepLink({ pairUrl, token, tunnel });
|
|
347
|
-
console.log(
|
|
348
|
-
`\n ${bold("Scan with the Pounce app")} ${dim("(Settings → Scan QR)")} ${bold("or your camera:")}\n`,
|
|
349
|
-
);
|
|
350
|
-
qrcode.generate(link, { small: true });
|
|
351
|
-
console.log(`\n ${dim("or open on the phone:")}\n ${dim(link)}\n`);
|
|
352
|
-
|
|
353
376
|
if (!wait) return;
|
|
354
377
|
console.log(
|
|
355
378
|
` Waiting for your phone… ${dim("(Ctrl-C is safe — the bridge keeps running; `pounce stop` stops it)")}`,
|
package/dist/launcher.mjs
CHANGED
|
@@ -4725,7 +4725,7 @@ var server = http.createServer(async (req, res) => {
|
|
|
4725
4725
|
return send(res, 200, {
|
|
4726
4726
|
...PAIR || {},
|
|
4727
4727
|
deepLink: pairDeepLink(),
|
|
4728
|
-
tunnel: tunnelInfo(),
|
|
4728
|
+
tunnel: tunnelEligible() ? tunnelInfo() : null,
|
|
4729
4729
|
token: TOKEN,
|
|
4730
4730
|
appVersion: APP_VERSION,
|
|
4731
4731
|
daemonOk: !!(daemon && daemon.pid),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "use-pounce",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Pair your phone with this machine in one command: npx use-pounce starts the Pounce bridge in the background and prints a QR to scan. Works over SSH — pairing rides an iroh p2p tunnel, no port-forwarding.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|