@leverageaiapps/theseus-server 1.0.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +165 -0
  3. package/dist/capture.d.ts +3 -0
  4. package/dist/capture.d.ts.map +1 -0
  5. package/dist/capture.js +134 -0
  6. package/dist/capture.js.map +1 -0
  7. package/dist/cloudflare-tunnel.d.ts +9 -0
  8. package/dist/cloudflare-tunnel.d.ts.map +1 -0
  9. package/dist/cloudflare-tunnel.js +218 -0
  10. package/dist/cloudflare-tunnel.js.map +1 -0
  11. package/dist/config.d.ts +7 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +84 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/context-extractor.d.ts +17 -0
  16. package/dist/context-extractor.d.ts.map +1 -0
  17. package/dist/context-extractor.js +118 -0
  18. package/dist/context-extractor.js.map +1 -0
  19. package/dist/index.d.ts +3 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +45 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/pty.d.ts +20 -0
  24. package/dist/pty.d.ts.map +1 -0
  25. package/dist/pty.js +148 -0
  26. package/dist/pty.js.map +1 -0
  27. package/dist/relay.d.ts +5 -0
  28. package/dist/relay.d.ts.map +1 -0
  29. package/dist/relay.js +131 -0
  30. package/dist/relay.js.map +1 -0
  31. package/dist/session.d.ts +5 -0
  32. package/dist/session.d.ts.map +1 -0
  33. package/dist/session.js +257 -0
  34. package/dist/session.js.map +1 -0
  35. package/dist/voice-recognition-modelscope.d.ts +50 -0
  36. package/dist/voice-recognition-modelscope.d.ts.map +1 -0
  37. package/dist/voice-recognition-modelscope.js +171 -0
  38. package/dist/voice-recognition-modelscope.js.map +1 -0
  39. package/dist/web-server.d.ts +6 -0
  40. package/dist/web-server.d.ts.map +1 -0
  41. package/dist/web-server.js +1971 -0
  42. package/dist/web-server.js.map +1 -0
  43. package/package.json +66 -0
  44. package/public/index.html +639 -0
  45. package/public/js/terminal-asr.js +508 -0
  46. package/public/js/terminal.js +514 -0
  47. package/public/js/voice-input.js +422 -0
  48. package/scripts/postinstall.js +66 -0
  49. package/scripts/verify-install.js +124 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 LeverageAI Apps
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,165 @@
1
+ # Theseus Server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@leverageaiapps/theseus-server.svg)](https://www.npmjs.com/package/@leverageaiapps/theseus-server)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ CLI tool to forward terminal sessions to your mobile device via Cloudflare Tunnel. **Code anywhere from your pocket.**
7
+
8
+ <p align="center">
9
+ <img src="https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen" alt="Node.js">
10
+ <img src="https://img.shields.io/badge/platform-macOS%20%7C%20Linux-blue" alt="Platform">
11
+ </p>
12
+
13
+ ## Features
14
+
15
+ - 🚀 **Instant Setup** - One command to start forwarding your terminal
16
+ - 📱 **Mobile Access** - Access your terminal from any device with a browser
17
+ - 🔒 **Secure** - PIN-protected sessions with automatic IP blocking
18
+ - 🌐 **No Port Forwarding** - Uses Cloudflare Quick Tunnel (no account needed)
19
+ - ⚡ **Real-time** - WebSocket-based communication for instant feedback
20
+ - 🎯 **PTY Support** - Full terminal emulation with node-pty
21
+
22
+ ## Prerequisites
23
+
24
+ ### Install cloudflared
25
+
26
+ Theseus requires `cloudflared` to create secure tunnels:
27
+
28
+ **macOS:**
29
+ ```bash
30
+ brew install cloudflared
31
+ ```
32
+
33
+ **Ubuntu/Debian:**
34
+ ```bash
35
+ sudo mkdir -p --mode=0755 /usr/share/keyrings
36
+ curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
37
+ echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
38
+ sudo apt-get update && sudo apt-get install cloudflared
39
+ ```
40
+
41
+ **Arch Linux:**
42
+ ```bash
43
+ sudo pacman -S cloudflared
44
+ ```
45
+
46
+ For other systems, see the [official installation guide](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/).
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ npm install -g @leverageaiapps/theseus-server
52
+ ```
53
+
54
+ **Verify Installation:**
55
+ ```bash
56
+ theseus --version
57
+ ```
58
+
59
+ ## Quick Start
60
+
61
+ ```bash
62
+ # Start a terminal session
63
+ theseus start
64
+
65
+ # Start with a specific command
66
+ theseus start claude
67
+ theseus start python
68
+ theseus start vim
69
+ ```
70
+
71
+ A QR code will appear - scan it with your phone and enter the 6-digit PIN to access your terminal!
72
+
73
+ ## Usage
74
+
75
+ ### Basic Commands
76
+
77
+ ```bash
78
+ # Start a terminal session
79
+ theseus start
80
+
81
+ # Start with a custom PIN
82
+ theseus start --pin 123456
83
+
84
+ # Start with a machine name
85
+ theseus start --name "My Laptop"
86
+
87
+ # Start a specific command
88
+ theseus start claude --pin 123456
89
+ ```
90
+
91
+ ### Options
92
+
93
+ | Option | Short | Description |
94
+ |--------|-------|-------------|
95
+ | `--name <name>` | `-n` | Set a custom machine name |
96
+ | `--pin <pin>` | `-p` | Set a custom 6-digit PIN |
97
+ | `--debug-asr` | | Enable verbose ASR logging |
98
+
99
+ ### Configuration
100
+
101
+ ```bash
102
+ # Show current configuration
103
+ theseus config --show
104
+ ```
105
+
106
+ ## How It Works
107
+
108
+ 1. Run `theseus start [command]` in your terminal
109
+ 2. Theseus starts a local web server and creates a Cloudflare tunnel
110
+ 3. A QR code appears with your unique URL
111
+ 4. Scan the QR code with your phone
112
+ 5. Enter the 6-digit PIN to access your terminal
113
+ 6. Your terminal is now accessible from your mobile device!
114
+
115
+ ## Security
116
+
117
+ - **PIN Protection**: Each session requires a 6-digit PIN
118
+ - **Rate Limiting**: Max 10 failed login attempts per IP
119
+ - **Auto-blocking**: IPs are temporarily blocked after too many failures
120
+ - **Session Cookies**: Authentication persists for 24 hours
121
+
122
+ ## Troubleshooting
123
+
124
+ ### Error: posix_spawnp failed
125
+
126
+ Fix permissions on the node-pty spawn-helper:
127
+
128
+ ```bash
129
+ # macOS ARM (M1/M2/M3)
130
+ chmod +x node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper
131
+
132
+ # macOS Intel
133
+ chmod +x node_modules/node-pty/prebuilds/darwin-x64/spawn-helper
134
+
135
+ # Linux x64
136
+ chmod +x node_modules/node-pty/prebuilds/linux-x64/spawn-helper
137
+ ```
138
+
139
+ ### cloudflared not found
140
+
141
+ Install cloudflared following the [Prerequisites](#prerequisites) section, then verify:
142
+
143
+ ```bash
144
+ cloudflared --version
145
+ ```
146
+
147
+ ## Contributing
148
+
149
+ Contributions are welcome! Please feel free to submit a Pull Request.
150
+
151
+ 1. Fork the repository
152
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
153
+ 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
154
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
155
+ 5. Open a Pull Request
156
+
157
+ ## License
158
+
159
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
160
+
161
+ ## Acknowledgments
162
+
163
+ - [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/) for secure tunneling
164
+ - [node-pty](https://github.com/microsoft/node-pty) for PTY support
165
+ - [xterm.js](https://xtermjs.org/) for terminal emulation in the browser
@@ -0,0 +1,3 @@
1
+ export declare function startCapture(sessionId: string, serverUrl: string): void;
2
+ export declare function stopCapture(): void;
3
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"AASA,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAuCvE;AAED,wBAAgB,WAAW,IAAI,IAAI,CASlC"}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.startCapture = startCapture;
40
+ exports.stopCapture = stopCapture;
41
+ const axios_1 = __importDefault(require("axios"));
42
+ const readline = __importStar(require("readline"));
43
+ // Buffer for accumulating partial lines
44
+ let lineBuffer = '';
45
+ let debounceTimer = null;
46
+ const DEBOUNCE_MS = 100;
47
+ let rl = null;
48
+ function startCapture(sessionId, serverUrl) {
49
+ // Only set up stdin capture if we're receiving piped input
50
+ if (process.stdin.isTTY) {
51
+ // Running interactively (not piped), don't capture stdin
52
+ console.log(' [Capture] Running in interactive mode');
53
+ return;
54
+ }
55
+ // Create readline interface for stdin (for piped input)
56
+ rl = readline.createInterface({
57
+ input: process.stdin,
58
+ output: process.stdout,
59
+ terminal: false,
60
+ });
61
+ // Listen for lines from Claude Code (piped input)
62
+ rl.on('line', (line) => {
63
+ // Accumulate lines and debounce sending
64
+ lineBuffer += line + '\n';
65
+ if (debounceTimer) {
66
+ clearTimeout(debounceTimer);
67
+ }
68
+ debounceTimer = setTimeout(() => {
69
+ sendMessage(sessionId, serverUrl, lineBuffer.trim());
70
+ lineBuffer = '';
71
+ }, DEBOUNCE_MS);
72
+ });
73
+ rl.on('close', () => {
74
+ // Send any remaining buffer
75
+ if (lineBuffer.trim()) {
76
+ sendMessage(sessionId, serverUrl, lineBuffer.trim());
77
+ }
78
+ console.log(' Input stream closed.');
79
+ });
80
+ console.log(' [Capture] Listening for piped input...');
81
+ }
82
+ function stopCapture() {
83
+ if (rl) {
84
+ rl.close();
85
+ rl = null;
86
+ }
87
+ if (debounceTimer) {
88
+ clearTimeout(debounceTimer);
89
+ debounceTimer = null;
90
+ }
91
+ }
92
+ async function sendMessage(sessionId, serverUrl, text) {
93
+ if (!text)
94
+ return;
95
+ try {
96
+ // Try to parse as Claude Code message format
97
+ const content = parseClaudeCodeMessage(text);
98
+ await axios_1.default.post(`${serverUrl}/api/sessions/${sessionId}/messages`, {
99
+ role: 'agent',
100
+ content,
101
+ });
102
+ }
103
+ catch (error) {
104
+ // Silently fail - we don't want to interrupt the user
105
+ if (process.env.DEBUG) {
106
+ console.error('Failed to send message:', error);
107
+ }
108
+ }
109
+ }
110
+ // Parse Claude Code output into structured format
111
+ function parseClaudeCodeMessage(text) {
112
+ // Check for tool use patterns
113
+ const toolUseMatch = text.match(/^(?:Using|Running|Executing|Calling)\s+(\w+)/i);
114
+ if (toolUseMatch) {
115
+ return {
116
+ type: 'tool-call',
117
+ name: toolUseMatch[1],
118
+ input: { description: text },
119
+ };
120
+ }
121
+ // Check for code blocks
122
+ if (text.includes('```')) {
123
+ return {
124
+ type: 'text',
125
+ text,
126
+ };
127
+ }
128
+ // Default to text
129
+ return {
130
+ type: 'text',
131
+ text,
132
+ };
133
+ }
134
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../src/capture.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Start Cloudflare Quick Tunnel
3
+ * Returns the generated tunnel URL
4
+ */
5
+ export declare function startTunnel(localPort?: number): Promise<string>;
6
+ export declare function stopTunnel(): void;
7
+ export declare function getTunnelUrl(): string | null;
8
+ export declare function isTunnelRunning(): boolean;
9
+ //# sourceMappingURL=cloudflare-tunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-tunnel.d.ts","sourceRoot":"","sources":["../src/cloudflare-tunnel.ts"],"names":[],"mappings":"AAmFA;;;GAGG;AACH,wBAAgB,WAAW,CAAC,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAcrE;AAqFD,wBAAgB,UAAU,IAAI,IAAI,CAMjC;AAED,wBAAgB,YAAY,IAAI,MAAM,GAAG,IAAI,CAE5C;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC"}
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.startTunnel = startTunnel;
37
+ exports.stopTunnel = stopTunnel;
38
+ exports.getTunnelUrl = getTunnelUrl;
39
+ exports.isTunnelRunning = isTunnelRunning;
40
+ const child_process_1 = require("child_process");
41
+ const os = __importStar(require("os"));
42
+ let tunnelProcess = null;
43
+ let tunnelUrl = null;
44
+ /**
45
+ * Get platform-specific installation instructions for cloudflared
46
+ */
47
+ function getInstallationInstructions() {
48
+ const platform = os.platform();
49
+ switch (platform) {
50
+ case 'darwin': // macOS
51
+ return `cloudflared is required for Theseus to work. Please install it using Homebrew:
52
+
53
+ brew install cloudflared
54
+
55
+ Alternatively, you can download it from: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/`;
56
+ case 'linux':
57
+ // Detect Linux distribution
58
+ const fs = require('fs');
59
+ let distroInstructions = '';
60
+ try {
61
+ // Check for common package managers
62
+ if (fs.existsSync('/usr/bin/apt') || fs.existsSync('/usr/bin/apt-get')) {
63
+ // Debian/Ubuntu
64
+ distroInstructions = ` # Add Cloudflare GPG key
65
+ sudo mkdir -p --mode=0755 /usr/share/keyrings
66
+ curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
67
+
68
+ # Add Cloudflare repository
69
+ echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
70
+
71
+ # Install cloudflared
72
+ sudo apt-get update && sudo apt-get install cloudflared`;
73
+ }
74
+ else if (fs.existsSync('/usr/bin/yum')) {
75
+ // CentOS/RHEL
76
+ distroInstructions = ` # Add Cloudflare repository
77
+ curl -fsSl https://pkg.cloudflare.com/cloudflared.repo | sudo tee /etc/yum.repos.d/cloudflared.repo
78
+
79
+ # Install cloudflared
80
+ sudo yum update && sudo yum install cloudflared`;
81
+ }
82
+ else if (fs.existsSync('/usr/bin/dnf')) {
83
+ // Fedora
84
+ distroInstructions = ` # Add Cloudflare repository
85
+ sudo dnf config-manager --add-repo https://pkg.cloudflare.com/cloudflared.repo
86
+
87
+ # Install cloudflared
88
+ sudo dnf install cloudflared`;
89
+ }
90
+ else if (fs.existsSync('/usr/bin/pacman')) {
91
+ // Arch Linux
92
+ distroInstructions = ` # Install from community repository
93
+ sudo pacman -S cloudflared`;
94
+ }
95
+ else {
96
+ // Generic Linux
97
+ distroInstructions = ` # Download and install manually
98
+ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
99
+ chmod +x cloudflared
100
+ sudo mv cloudflared /usr/local/bin/`;
101
+ }
102
+ }
103
+ catch (error) {
104
+ // Fallback to generic instructions
105
+ distroInstructions = ` # Download and install manually
106
+ curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -o cloudflared
107
+ chmod +x cloudflared
108
+ sudo mv cloudflared /usr/local/bin/`;
109
+ }
110
+ return `cloudflared is required for Theseus to work. Please install it:
111
+
112
+ ${distroInstructions}
113
+
114
+ For other distributions, see: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/`;
115
+ default:
116
+ return `cloudflared is required for Theseus to work. Please install it from:
117
+ https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/`;
118
+ }
119
+ }
120
+ /**
121
+ * Start Cloudflare Quick Tunnel
122
+ * Returns the generated tunnel URL
123
+ */
124
+ function startTunnel(localPort = 4020) {
125
+ return new Promise((resolve, reject) => {
126
+ // Check if cloudflared is installed
127
+ const which = (0, child_process_1.spawn)('which', ['cloudflared']);
128
+ which.on('close', (code) => {
129
+ if (code !== 0) {
130
+ reject(new Error(getInstallationInstructions()));
131
+ return;
132
+ }
133
+ startTunnelProcess(localPort, resolve, reject);
134
+ });
135
+ });
136
+ }
137
+ function startTunnelProcess(localPort, resolve, reject) {
138
+ // Create environment without proxy settings for cloudflared
139
+ const env = { ...process.env };
140
+ delete env.HTTP_PROXY;
141
+ delete env.HTTPS_PROXY;
142
+ delete env.http_proxy;
143
+ delete env.https_proxy;
144
+ delete env.ALL_PROXY;
145
+ delete env.all_proxy;
146
+ // Ensure localhost bypasses proxy
147
+ env.NO_PROXY = 'localhost,127.0.0.1,*.local';
148
+ env.no_proxy = env.NO_PROXY;
149
+ // Use --url for quick tunnel (no account needed)
150
+ // Bypass proxy to avoid TLS handshake issues
151
+ tunnelProcess = (0, child_process_1.spawn)('cloudflared', ['tunnel', '--url', `http://localhost:${localPort}`], {
152
+ stdio: ['ignore', 'pipe', 'pipe'],
153
+ env: env,
154
+ });
155
+ let urlFound = false;
156
+ const timeout = setTimeout(() => {
157
+ if (!urlFound) {
158
+ reject(new Error('Timeout waiting for tunnel URL'));
159
+ stopTunnel();
160
+ }
161
+ }, 30000); // 30 second timeout
162
+ // cloudflared outputs the URL to stderr
163
+ tunnelProcess.stderr?.on('data', (data) => {
164
+ const output = data.toString();
165
+ // Debug output
166
+ if (process.env.DEBUG) {
167
+ }
168
+ // Look for the tunnel URL in the output
169
+ // Format: "https://xxx-yyy-zzz.trycloudflare.com"
170
+ const urlMatch = output.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
171
+ if (urlMatch && !urlFound) {
172
+ urlFound = true;
173
+ clearTimeout(timeout);
174
+ tunnelUrl = urlMatch[0];
175
+ resolve(tunnelUrl);
176
+ }
177
+ });
178
+ tunnelProcess.stdout?.on('data', (data) => {
179
+ const output = data.toString();
180
+ if (process.env.DEBUG) {
181
+ }
182
+ // Also check stdout for URL
183
+ const urlMatch = output.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/);
184
+ if (urlMatch && !urlFound) {
185
+ urlFound = true;
186
+ clearTimeout(timeout);
187
+ tunnelUrl = urlMatch[0];
188
+ resolve(tunnelUrl);
189
+ }
190
+ });
191
+ tunnelProcess.on('error', (err) => {
192
+ clearTimeout(timeout);
193
+ console.error(' [Tunnel] Failed to start:', err);
194
+ reject(err);
195
+ });
196
+ tunnelProcess.on('close', (code) => {
197
+ if (!urlFound) {
198
+ clearTimeout(timeout);
199
+ reject(new Error(`cloudflared exited with code ${code}`));
200
+ }
201
+ tunnelProcess = null;
202
+ tunnelUrl = null;
203
+ });
204
+ }
205
+ function stopTunnel() {
206
+ if (tunnelProcess) {
207
+ tunnelProcess.kill('SIGTERM');
208
+ tunnelProcess = null;
209
+ tunnelUrl = null;
210
+ }
211
+ }
212
+ function getTunnelUrl() {
213
+ return tunnelUrl;
214
+ }
215
+ function isTunnelRunning() {
216
+ return tunnelProcess !== null && !tunnelProcess.killed;
217
+ }
218
+ //# sourceMappingURL=cloudflare-tunnel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloudflare-tunnel.js","sourceRoot":"","sources":["../src/cloudflare-tunnel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface Config {
2
+ serverUrl: string;
3
+ machineId: string;
4
+ }
5
+ export declare function getConfig(): Config;
6
+ export declare function setConfig(updates: Partial<Config>): void;
7
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,MAAM;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAgBD,wBAAgB,SAAS,IAAI,MAAM,CAalC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAexD"}
package/dist/config.js ADDED
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getConfig = getConfig;
37
+ exports.setConfig = setConfig;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ const CONFIG_DIR = path.join(os.homedir(), '.codingin');
42
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
43
+ const DEFAULT_CONFIG = {
44
+ serverUrl: process.env.CODINGIN_SERVER_URL || 'https://codingin.futuretech.social',
45
+ machineId: generateMachineId(),
46
+ };
47
+ function generateMachineId() {
48
+ const chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
49
+ let result = '';
50
+ for (let i = 0; i < 16; i++) {
51
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
52
+ }
53
+ return result;
54
+ }
55
+ function getConfig() {
56
+ try {
57
+ if (fs.existsSync(CONFIG_FILE)) {
58
+ const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
59
+ return { ...DEFAULT_CONFIG, ...JSON.parse(data) };
60
+ }
61
+ }
62
+ catch (error) {
63
+ console.error('Error reading config:', error);
64
+ }
65
+ // Create default config
66
+ setConfig(DEFAULT_CONFIG);
67
+ return DEFAULT_CONFIG;
68
+ }
69
+ function setConfig(updates) {
70
+ try {
71
+ if (!fs.existsSync(CONFIG_DIR)) {
72
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
73
+ }
74
+ const current = fs.existsSync(CONFIG_FILE)
75
+ ? JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'))
76
+ : DEFAULT_CONFIG;
77
+ const newConfig = { ...current, ...updates };
78
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
79
+ }
80
+ catch (error) {
81
+ console.error('Error writing config:', error);
82
+ }
83
+ }
84
+ //# sourceMappingURL=config.js.map