peer-term 1.4.3 → 1.4.5

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
@@ -12,7 +12,7 @@ npx peer-term
12
12
 
13
13
  This will start a terminal sharing session and give you a 6-digit code.
14
14
 
15
- Share this code with your peer. They can view your terminal by going to https://relay.dhananjaybalekar.in/ and entering the code.
15
+ Share this code with your peer. They can view your terminal by going to https://peerterm.dhananjaybalekar.in/ and entering the code.
16
16
 
17
17
  ## Global Installation
18
18
 
@@ -51,6 +51,8 @@ peer-term --verbose # enable debug logging
51
51
  - **Custom Start Path**: Set the starting directory with `--path`.
52
52
  - **Resilient Connections**: Both host and client get a 2-minute rejoin window if their IP changes or connection drops. PTY state is fully preserved — no session restart needed.
53
53
  - **Multi-Session**: Manage multiple simultaneous sessions with the interactive CLI menu.
54
+ - **QR Code Support**: Displays a terminal QR code for instant connection from mobile or tablet devices without manually entering the code.
55
+ - **Interactive Controls**: Manage sessions directly from the CLI (`n` for new session, `l` to list, `k` to kill, `a` to authorize fingerprint, `q` to quit).
54
56
 
55
57
  ## How It Works
56
58
 
package/bin/peer-term.js CHANGED
File without changes
package/package.json CHANGED
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "peer-term",
3
- "version": "1.4.3",
3
+ "version": "1.4.5",
4
4
  "license": "MIT",
5
5
  "description": "Share your terminal instantly using a 6-digit code or QR code. Encrypted. No config.",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/jay6205/Peer_Term",
8
+ "url": "https://github.com/jay6205/Peer_term.git",
9
9
  "directory": "host"
10
10
  },
11
- "homepage": "https://github.com/jay6205/Peer_Term#readme",
11
+ "homepage": "https://github.com/jay6205/Peer_term#readme",
12
12
  "bugs": {
13
- "url": "https://github.com/jay6205/Peer_Term/issues"
13
+ "url": "https://github.com/jay6205/Peer_term/issues"
14
14
  },
15
15
  "keywords": [
16
16
  "terminal",
package/src/index.js CHANGED
@@ -338,6 +338,12 @@ class Session {
338
338
  case 'code': {
339
339
  this.code = msg.code;
340
340
  this.hostToken = msg.hostToken || null;
341
+ const shareUrl = process.env.PEERTERM_CLIENT_URL || (
342
+ url.includes('relay.dhananjaybalekar.in')
343
+ ? 'https://peerterm.dhananjaybalekar.in'
344
+ : url.replace(/^wss:\/\//i, 'https://').replace(/^ws:\/\//i, 'http://')
345
+ );
346
+
341
347
  await printSessionBox({
342
348
  code: this.code,
343
349
  expiry: formatDuration(this.expiryMs),
@@ -345,7 +351,7 @@ class Session {
345
351
  mode: (this.readOnly ? 'Read-Only' : 'Read-Write') + (this.secureMode ? ' (Secure)' : ''),
346
352
  shell: this.shell,
347
353
  startPath: this.startPath,
348
- shareUrl: url.replace(/^wss:\/\//i, 'https://').replace(/^ws:\/\//i, 'http://')
354
+ shareUrl
349
355
  });
350
356
  if (resolve) resolve(this.code);
351
357
  break;
package/src/ui.js CHANGED
@@ -1,166 +1,166 @@
1
- /**
2
- * PeerTerm — CLI UI Module
3
- *
4
- * Handles all terminal output formatting:
5
- * - ASCII art banner
6
- * - Session code display box
7
- * - Help text
8
- * - Version display
9
- */
10
-
11
- import fs from 'fs';
12
- import path from 'path';
13
- import { fileURLToPath } from 'url';
14
- import qrcode from 'qrcode-terminal';
15
-
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = path.dirname(__filename);
18
-
19
- // ─── ASCII Banner ────────────────────────────────────────────────────────────
20
-
21
- const BANNER = `
22
- ██████╗ ███████╗███████╗██████╗ ████████╗███████╗██████╗ ███╗ ███╗
23
- ██╔══██╗██╔════╝██╔════╝██╔══██╗╚══██╔══╝██╔════╝██╔══██╗████╗ ████║
24
- ██████╔╝█████╗ █████╗ ██████╔╝ ██║ █████╗ ██████╔╝██╔████╔██║
25
- ██╔═══╝ ██╔══╝ ██╔══╝ ██╔══██╗ ██║ ██╔══╝ ██╔══██╗██║╚██╔╝██║
26
- ██║ ███████╗███████╗██║ ██║ ██║ ███████╗██║ ██║██║ ╚═╝ ██║
27
- ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
28
- Terminal sharing. Instant. Encrypted.`;
29
-
30
- /**
31
- * Print the startup ASCII art banner.
32
- */
33
- export function printBanner() {
34
- console.log(BANNER);
35
- console.log('');
36
- }
37
-
38
- // ─── Session Code Box ────────────────────────────────────────────────────────
39
-
40
- /**
41
- * Print the bordered session information box.
42
- *
43
- * @param {Object} opts
44
- * @param {string} opts.code - 6-digit session code
45
- * @param {string} opts.expiry - Formatted expiry string (e.g. "5 minute(s)")
46
- * @param {string} opts.mode - "Read-Write" or "Read-Only"
47
- * @param {string} opts.shell - Shell path (e.g. "/bin/zsh")
48
- * @param {string} [opts.startPath] - Starting directory for the session
49
- * @param {string} [opts.shareUrl] - URL to share (e.g. "https://peerterm.dev")
50
- */
51
- export async function printSessionBox({ code, expiry, rejoinWindow, mode, shell, startPath, shareUrl }) {
52
- const spacedCode = code.split('').join(' ');
53
- const url = shareUrl || 'https://peerterm.dev';
54
- const joinUrl = `${url}?code=${code}`;
55
-
56
- // Truncate long shell paths to keep box readable
57
- const shellDisplay = shell.length > 24 ? '...' + shell.slice(-21) : shell;
58
-
59
- // Truncate long start paths similarly
60
- const homeDir = process.env.HOME || process.env.USERPROFILE || '';
61
- let pathDisplay = startPath || homeDir;
62
- if (homeDir && pathDisplay.startsWith(homeDir)) {
63
- pathDisplay = '~' + pathDisplay.slice(homeDir.length);
64
- }
65
- if (pathDisplay.length > 30) pathDisplay = '...' + pathDisplay.slice(-27);
66
-
67
- // Calculate dynamic box width based on longest content
68
- const infoLines = [
69
- ` Session Code: ${spacedCode}`,
70
- ` Expires in: ${expiry}`,
71
- ` Rejoin Window: ${rejoinWindow}`,
72
- ` Mode: ${mode}`,
73
- ` Shell: ${shellDisplay}`,
74
- ` Path: ${pathDisplay}`,
75
- ];
76
- const shareLine = ` Share at: ${url}`;
77
- const allLines = [...infoLines, shareLine];
78
- const maxLen = Math.max(...allLines.map(l => l.length), 35);
79
- const innerWidth = maxLen + 3; // padding on right
80
-
81
- const hr = '─'.repeat(innerWidth);
82
- const emptyLine = ' '.repeat(innerWidth);
83
-
84
- console.log('');
85
- console.log(` ┌${hr}┐`);
86
- console.log(` │${emptyLine}│`);
87
- for (const line of infoLines) {
88
- console.log(` │${line.padEnd(innerWidth)}│`);
89
- }
90
- console.log(` │${emptyLine}│`);
91
- console.log(` │${shareLine.padEnd(innerWidth)}│`);
92
- console.log(` │${emptyLine}│`);
93
- console.log(` └${hr}┘`);
94
- console.log('');
95
-
96
- // Render QR code for instant scan-to-join
97
- try {
98
- const qrString = await new Promise((resolve) => {
99
- qrcode.generate(joinUrl, { small: true }, (qr) => {
100
- resolve(qr);
101
- });
102
- });
103
-
104
- console.log(' Scan to join:');
105
- console.log('');
106
- // Indent each QR line for alignment with the box
107
- const qrLines = qrString.split('\n');
108
- for (const line of qrLines) {
109
- if (line.length > 0) console.log(` ${line}`);
110
- }
111
- console.log('');
112
- console.log(` Or open: ${joinUrl}`);
113
- console.log('');
114
- } catch {
115
- // QR generation failed — not critical, code is still shown in the box
116
- }
117
- }
118
-
119
- // ─── Help Text ───────────────────────────────────────────────────────────────
120
-
121
- const HELP_TEXT = `
122
- Usage: peer-term [options]
123
-
124
- Options:
125
- --expiry <time> Session expiry time (e.g. 5m, 30s, 1h) [default: 5m]
126
- --rejoin <time> Reconnection window (e.g. 5m, 1h, 6h) [default: 2m]
127
- --readonly Share in view-only mode
128
- --secure Enable fingerprint verification for MITM protection
129
- --path <dir> Starting directory for the terminal session [default: home]
130
- --relay <url> Custom relay server URL
131
- --verbose Enable debug logging
132
- --help Show this help message
133
- --version Print version number
134
-
135
- Examples:
136
- peer-term Start session with defaults
137
- peer-term --expiry 10m Custom expiry
138
- peer-term --rejoin 30m Custom reconnection window
139
- peer-term --readonly View-only session
140
- peer-term --secure Require fingerprint verification
141
- peer-term --path ~/projects Start in ~/projects
142
- peer-term --verbose Debug logs
143
- peer-term --relay wss://custom Use custom relay server
144
- `;
145
-
146
- /**
147
- * Print CLI help text.
148
- */
149
- export function printHelp() {
150
- console.log(HELP_TEXT);
151
- }
152
-
153
- // ─── Version ─────────────────────────────────────────────────────────────────
154
-
155
- /**
156
- * Print the version number from package.json.
157
- */
158
- export function printVersion() {
159
- try {
160
- const pkgPath = path.join(__dirname, '..', 'package.json');
161
- const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
162
- console.log(`peer-term v${pkg.version}`);
163
- } catch {
164
- console.log('peer-term (version unknown)');
165
- }
166
- }
1
+ /**
2
+ * PeerTerm — CLI UI Module
3
+ *
4
+ * Handles all terminal output formatting:
5
+ * - ASCII art banner
6
+ * - Session code display box
7
+ * - Help text
8
+ * - Version display
9
+ */
10
+
11
+ import fs from 'fs';
12
+ import path from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ import qrcode from 'qrcode-terminal';
15
+
16
+ const __filename = fileURLToPath(import.meta.url);
17
+ const __dirname = path.dirname(__filename);
18
+
19
+ // ─── ASCII Banner ────────────────────────────────────────────────────────────
20
+
21
+ const BANNER = `
22
+ ██████╗ ███████╗███████╗██████╗ ████████╗███████╗██████╗ ███╗ ███╗
23
+ ██╔══██╗██╔════╝██╔════╝██╔══██╗╚══██╔══╝██╔════╝██╔══██╗████╗ ████║
24
+ ██████╔╝█████╗ █████╗ ██████╔╝ ██║ █████╗ ██████╔╝██╔████╔██║
25
+ ██╔═══╝ ██╔══╝ ██╔══╝ ██╔══██╗ ██║ ██╔══╝ ██╔══██╗██║╚██╔╝██║
26
+ ██║ ███████╗███████╗██║ ██║ ██║ ███████╗██║ ██║██║ ╚═╝ ██║
27
+ ╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
28
+ Terminal sharing. Instant. Encrypted.`;
29
+
30
+ /**
31
+ * Print the startup ASCII art banner.
32
+ */
33
+ export function printBanner() {
34
+ console.log(BANNER);
35
+ console.log('');
36
+ }
37
+
38
+ // ─── Session Code Box ────────────────────────────────────────────────────────
39
+
40
+ /**
41
+ * Print the bordered session information box.
42
+ *
43
+ * @param {Object} opts
44
+ * @param {string} opts.code - 6-digit session code
45
+ * @param {string} opts.expiry - Formatted expiry string (e.g. "5 minute(s)")
46
+ * @param {string} opts.mode - "Read-Write" or "Read-Only"
47
+ * @param {string} opts.shell - Shell path (e.g. "/bin/zsh")
48
+ * @param {string} [opts.startPath] - Starting directory for the session
49
+ * @param {string} [opts.shareUrl] - URL to share (e.g. "https://peerterm.dhananjaybalekar.in")
50
+ */
51
+ export async function printSessionBox({ code, expiry, rejoinWindow, mode, shell, startPath, shareUrl }) {
52
+ const spacedCode = code.split('').join(' ');
53
+ const url = shareUrl || 'https://peerterm.dhananjaybalekar.in';
54
+ const joinUrl = `${url}?code=${code}`;
55
+
56
+ // Truncate long shell paths to keep box readable
57
+ const shellDisplay = shell.length > 24 ? '...' + shell.slice(-21) : shell;
58
+
59
+ // Truncate long start paths similarly
60
+ const homeDir = process.env.HOME || process.env.USERPROFILE || '';
61
+ let pathDisplay = startPath || homeDir;
62
+ if (homeDir && pathDisplay.startsWith(homeDir)) {
63
+ pathDisplay = '~' + pathDisplay.slice(homeDir.length);
64
+ }
65
+ if (pathDisplay.length > 30) pathDisplay = '...' + pathDisplay.slice(-27);
66
+
67
+ // Calculate dynamic box width based on longest content
68
+ const infoLines = [
69
+ ` Session Code: ${spacedCode}`,
70
+ ` Expires in: ${expiry}`,
71
+ ` Rejoin Window: ${rejoinWindow}`,
72
+ ` Mode: ${mode}`,
73
+ ` Shell: ${shellDisplay}`,
74
+ ` Path: ${pathDisplay}`,
75
+ ];
76
+ const shareLine = ` Share at: ${url}`;
77
+ const allLines = [...infoLines, shareLine];
78
+ const maxLen = Math.max(...allLines.map(l => l.length), 35);
79
+ const innerWidth = maxLen + 3; // padding on right
80
+
81
+ const hr = '─'.repeat(innerWidth);
82
+ const emptyLine = ' '.repeat(innerWidth);
83
+
84
+ console.log('');
85
+ console.log(` ┌${hr}┐`);
86
+ console.log(` │${emptyLine}│`);
87
+ for (const line of infoLines) {
88
+ console.log(` │${line.padEnd(innerWidth)}│`);
89
+ }
90
+ console.log(` │${emptyLine}│`);
91
+ console.log(` │${shareLine.padEnd(innerWidth)}│`);
92
+ console.log(` │${emptyLine}│`);
93
+ console.log(` └${hr}┘`);
94
+ console.log('');
95
+
96
+ // Render QR code for instant scan-to-join
97
+ try {
98
+ const qrString = await new Promise((resolve) => {
99
+ qrcode.generate(joinUrl, { small: true }, (qr) => {
100
+ resolve(qr);
101
+ });
102
+ });
103
+
104
+ console.log(' Scan to join:');
105
+ console.log('');
106
+ // Indent each QR line for alignment with the box
107
+ const qrLines = qrString.split('\n');
108
+ for (const line of qrLines) {
109
+ if (line.length > 0) console.log(` ${line}`);
110
+ }
111
+ console.log('');
112
+ console.log(` Or open: ${joinUrl}`);
113
+ console.log('');
114
+ } catch {
115
+ // QR generation failed — not critical, code is still shown in the box
116
+ }
117
+ }
118
+
119
+ // ─── Help Text ───────────────────────────────────────────────────────────────
120
+
121
+ const HELP_TEXT = `
122
+ Usage: peer-term [options]
123
+
124
+ Options:
125
+ --expiry <time> Session expiry time (e.g. 5m, 30s, 1h) [default: 5m]
126
+ --rejoin <time> Reconnection window (e.g. 5m, 1h, 6h) [default: 2m]
127
+ --readonly Share in view-only mode
128
+ --secure Enable fingerprint verification for MITM protection
129
+ --path <dir> Starting directory for the terminal session [default: home]
130
+ --relay <url> Custom relay server URL
131
+ --verbose Enable debug logging
132
+ --help Show this help message
133
+ --version Print version number
134
+
135
+ Examples:
136
+ peer-term Start session with defaults
137
+ peer-term --expiry 10m Custom expiry
138
+ peer-term --rejoin 30m Custom reconnection window
139
+ peer-term --readonly View-only session
140
+ peer-term --secure Require fingerprint verification
141
+ peer-term --path ~/projects Start in ~/projects
142
+ peer-term --verbose Debug logs
143
+ peer-term --relay wss://custom Use custom relay server
144
+ `;
145
+
146
+ /**
147
+ * Print CLI help text.
148
+ */
149
+ export function printHelp() {
150
+ console.log(HELP_TEXT);
151
+ }
152
+
153
+ // ─── Version ─────────────────────────────────────────────────────────────────
154
+
155
+ /**
156
+ * Print the version number from package.json.
157
+ */
158
+ export function printVersion() {
159
+ try {
160
+ const pkgPath = path.join(__dirname, '..', 'package.json');
161
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
162
+ console.log(`peer-term v${pkg.version}`);
163
+ } catch {
164
+ console.log('peer-term (version unknown)');
165
+ }
166
+ }