cli-tunnel 1.0.0 → 1.0.2
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/index.js +74 -34
- package/package.json +17 -5
package/dist/index.js
CHANGED
|
@@ -220,47 +220,87 @@ async function main() {
|
|
|
220
220
|
console.log(` ${DIM}Port:${RESET} ${actualPort}`);
|
|
221
221
|
// Tunnel
|
|
222
222
|
if (hasTunnel) {
|
|
223
|
+
// Check if devtunnel is installed
|
|
224
|
+
let devtunnelInstalled = false;
|
|
223
225
|
try {
|
|
224
226
|
execSync('devtunnel --version', { stdio: 'pipe' });
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
const url = await new Promise((resolve, reject) => {
|
|
233
|
-
const timeout = setTimeout(() => reject(new Error('Tunnel timeout')), 15000);
|
|
234
|
-
let out = '';
|
|
235
|
-
hostProc.stdout?.on('data', (d) => {
|
|
236
|
-
out += d.toString();
|
|
237
|
-
const match = out.match(/https:\/\/[^\s]+/);
|
|
238
|
-
if (match) {
|
|
239
|
-
clearTimeout(timeout);
|
|
240
|
-
resolve(match[0]);
|
|
241
|
-
}
|
|
242
|
-
});
|
|
243
|
-
hostProc.on('error', (e) => { clearTimeout(timeout); reject(e); });
|
|
244
|
-
});
|
|
245
|
-
console.log(` ${GREEN}✓${RESET} Tunnel: ${BOLD}${url}${RESET}\n`);
|
|
246
|
-
try {
|
|
247
|
-
// @ts-ignore
|
|
248
|
-
const qr = (await import('qrcode-terminal'));
|
|
249
|
-
qr.default.generate(url, { small: true }, (code) => console.log(code));
|
|
227
|
+
devtunnelInstalled = true;
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
console.log(`\n ${YELLOW}⚠ devtunnel CLI not found!${RESET}\n`);
|
|
231
|
+
console.log(` ${BOLD}To enable remote access, install Microsoft Dev Tunnels:${RESET}\n`);
|
|
232
|
+
if (process.platform === 'win32') {
|
|
233
|
+
console.log(` ${GREEN}winget install Microsoft.devtunnel${RESET}`);
|
|
250
234
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
execSync(`devtunnel delete ${tunnelId} --force`, { stdio: 'pipe' });
|
|
235
|
+
else if (process.platform === 'darwin') {
|
|
236
|
+
console.log(` ${GREEN}brew install --cask devtunnel${RESET}`);
|
|
254
237
|
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
execSync(`devtunnel delete ${tunnelId} --force`, { stdio: 'pipe' });
|
|
238
|
+
else {
|
|
239
|
+
console.log(` ${GREEN}curl -sL https://aka.ms/DevTunnelCliInstall | bash${RESET}`);
|
|
258
240
|
}
|
|
259
|
-
|
|
241
|
+
console.log(`\n Then authenticate once:\n`);
|
|
242
|
+
console.log(` ${GREEN}devtunnel user login${RESET}\n`);
|
|
243
|
+
console.log(` ${DIM}More info: https://aka.ms/devtunnels/doc${RESET}\n`);
|
|
244
|
+
console.log(` ${DIM}Continuing without tunnel (local only)...${RESET}\n`);
|
|
260
245
|
}
|
|
261
|
-
|
|
262
|
-
|
|
246
|
+
// Check if logged in
|
|
247
|
+
if (devtunnelInstalled) {
|
|
248
|
+
try {
|
|
249
|
+
const userInfo = execSync('devtunnel user show', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
250
|
+
if (userInfo.includes('not logged in') || userInfo.includes('No user')) {
|
|
251
|
+
throw new Error('not logged in');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
console.log(`\n ${YELLOW}⚠ devtunnel not authenticated!${RESET}\n`);
|
|
256
|
+
console.log(` Run this once to log in:\n`);
|
|
257
|
+
console.log(` ${GREEN}devtunnel user login${RESET}\n`);
|
|
258
|
+
console.log(` ${DIM}Continuing without tunnel (local only)...${RESET}\n`);
|
|
259
|
+
devtunnelInstalled = false;
|
|
260
|
+
}
|
|
263
261
|
}
|
|
262
|
+
if (devtunnelInstalled) {
|
|
263
|
+
try {
|
|
264
|
+
const labels = ['cli-tunnel', sanitizeLabel(sessionName || command), sanitizeLabel(repo), sanitizeLabel(branch), sanitizeLabel(machine), `port-${actualPort}`]
|
|
265
|
+
.map(l => `--labels ${l}`).join(' ');
|
|
266
|
+
const createOut = execSync(`devtunnel create ${labels} --expiration 1d --json`, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
267
|
+
const tunnelId = JSON.parse(createOut).tunnel?.tunnelId?.split('.')[0];
|
|
268
|
+
const cluster = JSON.parse(createOut).tunnel?.tunnelId?.split('.')[1] || 'euw';
|
|
269
|
+
execSync(`devtunnel port create ${tunnelId} -p ${actualPort} --protocol http`, { stdio: 'pipe' });
|
|
270
|
+
const hostProc = spawn('devtunnel', ['host', tunnelId], { stdio: 'pipe', detached: false });
|
|
271
|
+
const url = await new Promise((resolve, reject) => {
|
|
272
|
+
const timeout = setTimeout(() => reject(new Error('Tunnel timeout')), 15000);
|
|
273
|
+
let out = '';
|
|
274
|
+
hostProc.stdout?.on('data', (d) => {
|
|
275
|
+
out += d.toString();
|
|
276
|
+
const match = out.match(/https:\/\/[^\s]+/);
|
|
277
|
+
if (match) {
|
|
278
|
+
clearTimeout(timeout);
|
|
279
|
+
resolve(match[0]);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
hostProc.on('error', (e) => { clearTimeout(timeout); reject(e); });
|
|
283
|
+
});
|
|
284
|
+
console.log(` ${GREEN}✓${RESET} Tunnel: ${BOLD}${url}${RESET}\n`);
|
|
285
|
+
try {
|
|
286
|
+
// @ts-ignore
|
|
287
|
+
const qr = (await import('qrcode-terminal'));
|
|
288
|
+
qr.default.generate(url, { small: true }, (code) => console.log(code));
|
|
289
|
+
}
|
|
290
|
+
catch { }
|
|
291
|
+
process.on('SIGINT', () => { hostProc.kill(); try {
|
|
292
|
+
execSync(`devtunnel delete ${tunnelId} --force`, { stdio: 'pipe' });
|
|
293
|
+
}
|
|
294
|
+
catch { } });
|
|
295
|
+
process.on('exit', () => { hostProc.kill(); try {
|
|
296
|
+
execSync(`devtunnel delete ${tunnelId} --force`, { stdio: 'pipe' });
|
|
297
|
+
}
|
|
298
|
+
catch { } });
|
|
299
|
+
}
|
|
300
|
+
catch (err) {
|
|
301
|
+
console.log(` ${YELLOW}⚠${RESET} Tunnel failed: ${err.message}\n`);
|
|
302
|
+
}
|
|
303
|
+
} // end if (devtunnelInstalled)
|
|
264
304
|
}
|
|
265
305
|
console.log(` ${DIM}Starting ${command}...${RESET}\n`);
|
|
266
306
|
// Spawn PTY
|
package/package.json
CHANGED
|
@@ -1,23 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-tunnel",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Tunnel any CLI app to your phone - PTY + devtunnel + xterm.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"cli-tunnel": "
|
|
8
|
+
"cli-tunnel": "dist/index.js"
|
|
9
9
|
},
|
|
10
|
-
"files": [
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"remote-ui"
|
|
13
|
+
],
|
|
11
14
|
"scripts": {
|
|
12
15
|
"build": "tsc",
|
|
13
16
|
"test": "vitest run"
|
|
14
17
|
},
|
|
15
|
-
"keywords": [
|
|
18
|
+
"keywords": [
|
|
19
|
+
"cli",
|
|
20
|
+
"tunnel",
|
|
21
|
+
"remote",
|
|
22
|
+
"pty",
|
|
23
|
+
"xterm",
|
|
24
|
+
"devtunnel",
|
|
25
|
+
"copilot",
|
|
26
|
+
"terminal"
|
|
27
|
+
],
|
|
16
28
|
"author": "Tamir Dresher",
|
|
17
29
|
"license": "MIT",
|
|
18
30
|
"repository": {
|
|
19
31
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/tamirdresher/cli-tunnel.git"
|
|
32
|
+
"url": "git+https://github.com/tamirdresher/cli-tunnel.git"
|
|
21
33
|
},
|
|
22
34
|
"engines": {
|
|
23
35
|
"node": ">=22.0.0"
|