tinyagent 1.0.5 → 1.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/README.md CHANGED
@@ -24,7 +24,7 @@ tinyagent my-session
24
24
 
25
25
  3. Your local terminal is now accessible from your phone!
26
26
 
27
- **Bonus**: If you have Claude CLI installed, it will automatically start Claude for you!
27
+ **Bonus**: If you have Claude CLI installed, it will automatically start Claude for you! Claude will be able to see and interact with your terminal session.
28
28
 
29
29
  ## Features
30
30
 
@@ -64,24 +64,53 @@ tinyagent --shell /bin/zsh
64
64
  tinyagent --no-claude
65
65
  ```
66
66
 
67
- ### Options:
68
- - `--session-id <id>` - Specify session ID (alternative to positional argument)
67
+ ### Advanced: Run a server alongside your shell
68
+ ```bash
69
+ tinyagent -c "npm run dev" -p 3000
70
+ ```
71
+
72
+ This runs a dev server in parallel with your shell session (legacy feature - HTTP tunneling now auto-detects running servers).
73
+
74
+ ### All Options:
75
+ - `[sessionId]` - Session ID as first argument (optional, auto-generated if not provided)
76
+ - `--session-id <id>` - Session ID (alternative to positional argument)
69
77
  - `-r, --relay <url>` - Relay server URL (default: wss://relay.tinyagent.app)
70
78
  - `-s, --shell <shell>` - Shell to use (default: $SHELL or /bin/bash)
79
+ - `-c, --command <cmd>` - Run a server command in parallel (legacy - auto-detection preferred)
80
+ - `-p, --port <port>` - Port for the server command (default: 3000)
81
+ - `--no-tunnel` - Disable localtunnel integration
71
82
  - `--no-claude` - Do not auto-start Claude CLI
72
83
  - `-v, --verbose` - Show detailed debug output
84
+ - `-V, --version` - Show version number
85
+ - `-h, --help` - Show help
73
86
 
74
87
  ## HTTP Tunneling
75
88
 
76
- When you have local development servers running (e.g., on port 3000), tinyagent automatically exposes them:
89
+ Tinyagent automatically detects and exposes your local development servers! No configuration needed.
90
+
91
+ When you have servers running on common ports (3000, 3001, 4000, 4200, 5000, 5173, 8000, 8080, 8081, 9000), you'll see:
77
92
 
78
93
  ```
79
- [HTTP] Exposing ports: 3000
94
+ [HTTP] Exposing ports: 3000, 5173
80
95
  [HTTP] Access your dev server at:
81
96
  https://my-session-3000.tinyagent.app/
97
+ https://my-session-5173.tinyagent.app/
82
98
  ```
83
99
 
84
- You can access your local dev server from any browser using this URL.
100
+ Access your local dev servers from any browser - perfect for testing on mobile devices!
101
+
102
+ ## Environment Variables
103
+
104
+ You can set these environment variables to customize default behavior:
105
+
106
+ - `RELAY_URL` - Default relay server URL (instead of using `-r` flag each time)
107
+ - `SHELL` - Default shell to use (automatically detected from your system)
108
+
109
+ Example:
110
+ ```bash
111
+ export RELAY_URL=ws://localhost:8080
112
+ tinyagent
113
+ ```
85
114
 
86
115
  ## Security
87
116
 
@@ -89,6 +118,34 @@ You can access your local dev server from any browser using this URL.
89
118
  - Session IDs are private - only those with the ID can connect
90
119
  - Connections are encrypted with WSS (WebSocket Secure)
91
120
 
121
+ ## Troubleshooting
122
+
123
+ ### Debug Mode
124
+ If you're experiencing issues, run with verbose output:
125
+ ```bash
126
+ tinyagent -v
127
+ # or
128
+ tinyagent --verbose
129
+ ```
130
+
131
+ This will show:
132
+ - WebSocket connection details
133
+ - Terminal resize events
134
+ - Input source tracking (local vs mobile)
135
+ - HTTP port detection
136
+
137
+ ### Common Issues
138
+
139
+ **Claude not starting automatically?**
140
+ - Make sure Claude CLI is installed and in your PATH
141
+ - Try running `which claude` to verify installation
142
+ - Use `--no-claude` to disable auto-start
143
+
144
+ **Dev server not accessible?**
145
+ - Ensure your server is running on a standard port (3000, 3001, 4000, 4200, 5000, 5173, 8000, 8080, 8081, 9000)
146
+ - Check that the server is bound to `localhost` or `0.0.0.0`, not just `127.0.0.1`
147
+ - Look for the `[HTTP] Exposing ports:` message in the output
148
+
92
149
  ## Learn More
93
150
 
94
151
  - Website: https://tinyagent.app
@@ -0,0 +1,14 @@
1
+ export declare class AuthClient {
2
+ private authUrl;
3
+ private configPath;
4
+ private token?;
5
+ constructor(authUrl?: string);
6
+ private loadToken;
7
+ private saveToken;
8
+ isAuthenticated(): boolean;
9
+ getToken(): string | undefined;
10
+ authenticate(): Promise<boolean>;
11
+ logout(): void;
12
+ whoami(): void;
13
+ }
14
+ //# sourceMappingURL=auth-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-client.d.ts","sourceRoot":"","sources":["../src/auth-client.ts"],"names":[],"mappings":"AAkBA,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAY;gBAEd,OAAO,GAAE,MAAqC;IAM1D,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,SAAS;IAaV,eAAe,IAAI,OAAO;IAQ1B,QAAQ,IAAI,MAAM,GAAG,SAAS;IAIxB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IA+FtC,MAAM,IAAI,IAAI;IAYd,MAAM,IAAI,IAAI;CAiBtB"}
@@ -0,0 +1,165 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AuthClient = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const open_1 = __importDefault(require("open"));
13
+ class AuthClient {
14
+ authUrl;
15
+ configPath;
16
+ token;
17
+ constructor(authUrl = 'https://auth.tinyagent.app') {
18
+ this.authUrl = process.env.AUTH_URL || authUrl;
19
+ this.configPath = path_1.default.join(os_1.default.homedir(), '.tinyagent', 'auth.json');
20
+ this.loadToken();
21
+ }
22
+ loadToken() {
23
+ try {
24
+ if (fs_1.default.existsSync(this.configPath)) {
25
+ const data = fs_1.default.readFileSync(this.configPath, 'utf-8');
26
+ this.token = JSON.parse(data);
27
+ }
28
+ }
29
+ catch (error) {
30
+ // Ignore errors, token will be undefined
31
+ }
32
+ }
33
+ saveToken(token) {
34
+ try {
35
+ const dir = path_1.default.dirname(this.configPath);
36
+ if (!fs_1.default.existsSync(dir)) {
37
+ fs_1.default.mkdirSync(dir, { recursive: true });
38
+ }
39
+ fs_1.default.writeFileSync(this.configPath, JSON.stringify(token, null, 2));
40
+ this.token = token;
41
+ }
42
+ catch (error) {
43
+ console.error(chalk_1.default.yellow('Warning: Could not save auth token'));
44
+ }
45
+ }
46
+ isAuthenticated() {
47
+ if (!this.token)
48
+ return false;
49
+ if (this.token.expiresAt && this.token.expiresAt < Date.now()) {
50
+ return false;
51
+ }
52
+ return true;
53
+ }
54
+ getToken() {
55
+ return this.isAuthenticated() ? this.token?.accessToken : undefined;
56
+ }
57
+ async authenticate() {
58
+ console.log(chalk_1.default.cyan('\n🔐 Authentication required'));
59
+ // Generate PKCE challenge
60
+ const codeVerifier = crypto_1.default.randomBytes(32).toString('base64url');
61
+ const codeChallenge = crypto_1.default
62
+ .createHash('sha256')
63
+ .update(codeVerifier)
64
+ .digest('base64url');
65
+ try {
66
+ // Request device code
67
+ const deviceResponse = await fetch(`${this.authUrl}/api/auth/device`, {
68
+ method: 'POST',
69
+ headers: { 'Content-Type': 'application/json' },
70
+ body: JSON.stringify({ codeChallenge }),
71
+ });
72
+ if (!deviceResponse.ok) {
73
+ throw new Error('Failed to get device code');
74
+ }
75
+ const deviceData = await deviceResponse.json();
76
+ console.log(chalk_1.default.white('\nTo authenticate, visit:'));
77
+ console.log(chalk_1.default.green.bold(deviceData.verificationUrl));
78
+ console.log(chalk_1.default.white('\nVerification code: ') + chalk_1.default.yellow.bold(deviceData.userCode));
79
+ // Open browser
80
+ try {
81
+ await (0, open_1.default)(deviceData.verificationUrl);
82
+ console.log(chalk_1.default.gray('(Browser should open automatically)'));
83
+ }
84
+ catch {
85
+ console.log(chalk_1.default.gray('(Please open the URL manually in your browser)'));
86
+ }
87
+ console.log(chalk_1.default.gray('\nWaiting for authentication...'));
88
+ // Poll for authentication
89
+ const startTime = Date.now();
90
+ const expiresIn = deviceData.expiresIn * 1000; // Convert to ms
91
+ const interval = deviceData.interval * 1000; // Convert to ms
92
+ while (Date.now() - startTime < expiresIn) {
93
+ await new Promise(resolve => setTimeout(resolve, interval));
94
+ const pollResponse = await fetch(`${this.authUrl}/api/auth/cli?device_code=${deviceData.deviceCode}`);
95
+ if (!pollResponse.ok)
96
+ continue;
97
+ const pollData = await pollResponse.json();
98
+ if (pollData.status === 'authenticated') {
99
+ // Exchange for tokens
100
+ const tokenResponse = await fetch(`${this.authUrl}/api/auth/token`, {
101
+ method: 'POST',
102
+ headers: { 'Content-Type': 'application/json' },
103
+ body: JSON.stringify({
104
+ grantType: 'authorization_code',
105
+ code: pollData.accessToken, // Using token as code for simplicity
106
+ codeVerifier,
107
+ }),
108
+ });
109
+ if (!tokenResponse.ok) {
110
+ throw new Error('Failed to exchange code for tokens');
111
+ }
112
+ const tokenData = await tokenResponse.json();
113
+ // Save token
114
+ this.saveToken({
115
+ accessToken: tokenData.accessToken,
116
+ refreshToken: tokenData.refreshToken,
117
+ user: tokenData.user,
118
+ expiresAt: Date.now() + (tokenData.expiresIn * 1000),
119
+ });
120
+ console.log(chalk_1.default.green('\n✓ Authentication successful!'));
121
+ if (tokenData.user?.email) {
122
+ console.log(chalk_1.default.gray(`Logged in as: ${tokenData.user.email}`));
123
+ }
124
+ return true;
125
+ }
126
+ }
127
+ console.log(chalk_1.default.red('\n✗ Authentication timed out'));
128
+ return false;
129
+ }
130
+ catch (error) {
131
+ console.error(chalk_1.default.red('\n✗ Authentication failed:'), error);
132
+ return false;
133
+ }
134
+ }
135
+ logout() {
136
+ try {
137
+ if (fs_1.default.existsSync(this.configPath)) {
138
+ fs_1.default.unlinkSync(this.configPath);
139
+ }
140
+ this.token = undefined;
141
+ console.log(chalk_1.default.green('✓ Logged out successfully'));
142
+ }
143
+ catch (error) {
144
+ console.error(chalk_1.default.red('✗ Logout failed:'), error);
145
+ }
146
+ }
147
+ whoami() {
148
+ if (!this.isAuthenticated()) {
149
+ console.log(chalk_1.default.yellow('Not authenticated. Run "tinyagent login" to authenticate.'));
150
+ return;
151
+ }
152
+ if (this.token?.user) {
153
+ console.log(chalk_1.default.cyan('Current user:'));
154
+ console.log(` ID: ${this.token.user.id}`);
155
+ if (this.token.user.email) {
156
+ console.log(` Email: ${this.token.user.email}`);
157
+ }
158
+ if (this.token.user.name) {
159
+ console.log(` Name: ${this.token.user.name}`);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ exports.AuthClient = AuthClient;
165
+ //# sourceMappingURL=auth-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-client.js","sourceRoot":"","sources":["../src/auth-client.ts"],"names":[],"mappings":"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"}
package/dist/cli.js CHANGED
@@ -7,37 +7,41 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const commander_1 = require("commander");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const dotenv_1 = require("dotenv");
10
- const child_process_1 = require("child_process");
11
10
  const shell_client_v2_1 = require("./shell-client-v2");
12
11
  const qr_generator_1 = require("./qr-generator");
12
+ const firebase_auth_simple_1 = require("./firebase-auth-simple");
13
13
  (0, dotenv_1.config)();
14
- // Function to check if Claude is available and start it
15
- function checkAndStartClaude(sessionId) {
16
- try {
17
- // Check if claude command exists
18
- (0, child_process_1.execSync)('which claude', { stdio: 'ignore' });
19
- console.log(chalk_1.default.green('\n✓ Claude detected - starting Claude session...'));
20
- // Start claude in the background
21
- const claudeProcess = (0, child_process_1.spawn)('claude', [], {
22
- detached: true,
23
- stdio: 'ignore'
24
- });
25
- claudeProcess.unref();
26
- console.log(chalk_1.default.gray('Claude is running in the background'));
27
- console.log(chalk_1.default.yellow(`\nTip: You can now ask Claude to connect to your shell session "${sessionId}"`));
28
- }
29
- catch (error) {
30
- // Claude not found or failed to start - silently continue
31
- if (process.env.DEBUG || process.argv.includes('--verbose')) {
32
- console.log(chalk_1.default.gray('Claude not found or could not be started'));
33
- }
34
- }
35
- }
36
14
  const program = new commander_1.Command();
15
+ // Authentication commands
16
+ program
17
+ .command('login')
18
+ .description('Authenticate with Tinyagent')
19
+ .action(async () => {
20
+ const authClient = new firebase_auth_simple_1.FirebaseAuthClient();
21
+ const success = await authClient.authenticate();
22
+ process.exit(success ? 0 : 1);
23
+ });
24
+ program
25
+ .command('logout')
26
+ .description('Log out from Tinyagent')
27
+ .action(() => {
28
+ const authClient = new firebase_auth_simple_1.FirebaseAuthClient();
29
+ authClient.logout();
30
+ process.exit(0);
31
+ });
32
+ program
33
+ .command('whoami')
34
+ .description('Display current user information')
35
+ .action(() => {
36
+ const authClient = new firebase_auth_simple_1.FirebaseAuthClient();
37
+ authClient.whoami();
38
+ process.exit(0);
39
+ });
40
+ // Main shell command
37
41
  program
38
42
  .name('tinyagent')
39
43
  .description('Connect your local shell to any device')
40
- .version('1.0.5')
44
+ .version('1.2.0')
41
45
  .argument('[sessionId]', 'Session ID to connect to (optional, auto-generated if not provided)')
42
46
  .option('--session-id <id>', 'Session ID (alternative to positional argument)')
43
47
  .option('-r, --relay <url>', 'Relay server URL', process.env.RELAY_URL || 'wss://relay.tinyagent.app')
@@ -47,6 +51,9 @@ program
47
51
  .option('--no-tunnel', 'Disable tunnel creation')
48
52
  .option('--no-claude', 'Do not auto-start Claude')
49
53
  .option('-v, --verbose', 'Show detailed debug output')
54
+ .option('--password <password>', 'Password required for mobile clients to connect')
55
+ .option('--resume', 'Resume the last Claude session')
56
+ .option('--continue', 'Continue the last Claude session (alias for --resume)')
50
57
  .action(async (sessionIdArg, options) => {
51
58
  // Determine session ID from argument or option, or generate one
52
59
  let sessionId = sessionIdArg || options.sessionId;
@@ -65,13 +72,13 @@ program
65
72
  shell: options.shell,
66
73
  serverCommand: options.command,
67
74
  serverPort: parseInt(options.port),
68
- createTunnel: options.tunnel
75
+ createTunnel: options.tunnel,
76
+ autoStartClaude: !options.noClaude,
77
+ password: options.password,
78
+ resumeClaude: options.resume || options.continue,
79
+ verbose: options.verbose
69
80
  });
70
81
  await client.connect();
71
- // Auto-start Claude if available and not disabled
72
- if (!options.noClaude) {
73
- checkAndStartClaude(sessionId);
74
- }
75
82
  process.on('SIGINT', () => {
76
83
  console.log(chalk_1.default.yellow('\nDisconnecting...'));
77
84
  client.disconnect();
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ interface FirebaseUser {
2
+ uid: string;
3
+ email?: string | null;
4
+ displayName?: string | null;
5
+ photoURL?: string | null;
6
+ }
7
+ export declare class FirebaseAuthClient {
8
+ private configPath;
9
+ private token?;
10
+ constructor();
11
+ private loadToken;
12
+ private saveToken;
13
+ isAuthenticated(): boolean;
14
+ getToken(): string | undefined;
15
+ getUser(): FirebaseUser | undefined;
16
+ authenticate(): Promise<boolean>;
17
+ logout(): void;
18
+ whoami(): void;
19
+ }
20
+ export {};
21
+ //# sourceMappingURL=firebase-auth-simple.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"firebase-auth-simple.d.ts","sourceRoot":"","sources":["../src/firebase-auth-simple.ts"],"names":[],"mappings":"AAQA,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AASD,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAY;;IAO1B,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,SAAS;IAaV,eAAe,IAAI,OAAO;IAQ1B,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B,OAAO,IAAI,YAAY,GAAG,SAAS;IAI7B,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC;IA0ItC,MAAM,IAAI,IAAI;IAYd,MAAM,IAAI,IAAI;CAkBtB"}
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FirebaseAuthClient = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const os_1 = __importDefault(require("os"));
11
+ const open_1 = __importDefault(require("open"));
12
+ const http_1 = __importDefault(require("http"));
13
+ const url_1 = require("url");
14
+ class FirebaseAuthClient {
15
+ configPath;
16
+ token;
17
+ constructor() {
18
+ this.configPath = path_1.default.join(os_1.default.homedir(), '.tinyagent', 'auth.json');
19
+ this.loadToken();
20
+ }
21
+ loadToken() {
22
+ try {
23
+ if (fs_1.default.existsSync(this.configPath)) {
24
+ const data = fs_1.default.readFileSync(this.configPath, 'utf-8');
25
+ this.token = JSON.parse(data);
26
+ }
27
+ }
28
+ catch (error) {
29
+ // Ignore errors, token will be undefined
30
+ }
31
+ }
32
+ saveToken(token) {
33
+ try {
34
+ const dir = path_1.default.dirname(this.configPath);
35
+ if (!fs_1.default.existsSync(dir)) {
36
+ fs_1.default.mkdirSync(dir, { recursive: true });
37
+ }
38
+ fs_1.default.writeFileSync(this.configPath, JSON.stringify(token, null, 2));
39
+ this.token = token;
40
+ }
41
+ catch (error) {
42
+ console.error(chalk_1.default.yellow('Warning: Could not save auth token'));
43
+ }
44
+ }
45
+ isAuthenticated() {
46
+ if (!this.token)
47
+ return false;
48
+ if (this.token.expiresAt && this.token.expiresAt < Date.now()) {
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ getToken() {
54
+ return this.isAuthenticated() ? this.token?.idToken : undefined;
55
+ }
56
+ getUser() {
57
+ return this.isAuthenticated() ? this.token?.user : undefined;
58
+ }
59
+ async authenticate() {
60
+ console.log(chalk_1.default.cyan('\n🔐 Authenticating with Firebase'));
61
+ try {
62
+ // Create local server to receive the callback
63
+ const server = http_1.default.createServer();
64
+ const port = 9005;
65
+ return new Promise((resolve) => {
66
+ let resolved = false;
67
+ server.on('request', async (req, res) => {
68
+ const url = new url_1.URL(req.url, `http://localhost:${port}`);
69
+ if (url.pathname === '/auth/callback') {
70
+ const idToken = url.searchParams.get('token');
71
+ const uid = url.searchParams.get('uid');
72
+ const email = url.searchParams.get('email');
73
+ const name = url.searchParams.get('name');
74
+ if (idToken && uid) {
75
+ try {
76
+ // Save token
77
+ this.saveToken({
78
+ idToken,
79
+ user: {
80
+ uid,
81
+ email: email || null,
82
+ displayName: name || null,
83
+ photoURL: null,
84
+ },
85
+ expiresAt: Date.now() + (60 * 60 * 1000), // 1 hour
86
+ });
87
+ // Send success response
88
+ res.writeHead(200, { 'Content-Type': 'text/html' });
89
+ res.end(`
90
+ <!DOCTYPE html>
91
+ <html>
92
+ <head>
93
+ <title>Authentication Successful</title>
94
+ <style>
95
+ body {
96
+ font-family: -apple-system, system-ui, sans-serif;
97
+ display: flex;
98
+ justify-content: center;
99
+ align-items: center;
100
+ height: 100vh;
101
+ margin: 0;
102
+ background: #000;
103
+ color: #0f0;
104
+ }
105
+ .success { text-align: center; }
106
+ h1 { font-size: 48px; margin: 0; }
107
+ p { color: #888; margin-top: 10px; }
108
+ </style>
109
+ </head>
110
+ <body>
111
+ <div class="success">
112
+ <h1>✓</h1>
113
+ <p>Authentication successful! You can close this window.</p>
114
+ </div>
115
+ <script>setTimeout(() => window.close(), 2000)</script>
116
+ </body>
117
+ </html>
118
+ `);
119
+ console.log(chalk_1.default.green('\n✓ Authentication successful!'));
120
+ if (email) {
121
+ console.log(chalk_1.default.gray(`Logged in as: ${email}`));
122
+ }
123
+ if (!resolved) {
124
+ resolved = true;
125
+ server.close();
126
+ resolve(true);
127
+ }
128
+ }
129
+ catch (error) {
130
+ console.error(chalk_1.default.red('Failed to process authentication'));
131
+ res.writeHead(400);
132
+ res.end('Authentication failed');
133
+ if (!resolved) {
134
+ resolved = true;
135
+ server.close();
136
+ resolve(false);
137
+ }
138
+ }
139
+ }
140
+ else {
141
+ res.writeHead(400);
142
+ res.end('Missing authentication data');
143
+ if (!resolved) {
144
+ resolved = true;
145
+ server.close();
146
+ resolve(false);
147
+ }
148
+ }
149
+ }
150
+ else {
151
+ res.writeHead(404);
152
+ res.end('Not found');
153
+ }
154
+ });
155
+ server.listen(port, async () => {
156
+ // For now, we'll use a simple auth page hosted on Firebase
157
+ // In production, this would be your Firebase Hosting URL
158
+ const authUrl = `https://tinyagent-fab3c.firebaseapp.com/auth/cli?redirect=http://localhost:${port}/auth/callback`;
159
+ console.log(chalk_1.default.white('\nTo authenticate, visit:'));
160
+ console.log(chalk_1.default.green.bold(authUrl));
161
+ // Open browser
162
+ try {
163
+ await (0, open_1.default)(authUrl);
164
+ console.log(chalk_1.default.gray('\n(Browser should open automatically)'));
165
+ }
166
+ catch {
167
+ console.log(chalk_1.default.gray('\n(Please open the URL manually in your browser)'));
168
+ }
169
+ console.log(chalk_1.default.gray('\nWaiting for authentication...'));
170
+ });
171
+ // Timeout after 5 minutes
172
+ setTimeout(() => {
173
+ if (server.listening && !resolved) {
174
+ console.log(chalk_1.default.red('\n✗ Authentication timed out'));
175
+ resolved = true;
176
+ server.close();
177
+ resolve(false);
178
+ }
179
+ }, 5 * 60 * 1000);
180
+ });
181
+ }
182
+ catch (error) {
183
+ console.error(chalk_1.default.red('\n✗ Authentication failed:'), error);
184
+ return false;
185
+ }
186
+ }
187
+ logout() {
188
+ try {
189
+ if (fs_1.default.existsSync(this.configPath)) {
190
+ fs_1.default.unlinkSync(this.configPath);
191
+ }
192
+ this.token = undefined;
193
+ console.log(chalk_1.default.green('✓ Logged out successfully'));
194
+ }
195
+ catch (error) {
196
+ console.error(chalk_1.default.red('✗ Logout failed:'), error);
197
+ }
198
+ }
199
+ whoami() {
200
+ if (!this.isAuthenticated()) {
201
+ console.log(chalk_1.default.yellow('Not authenticated. Run "tinyagent login" to authenticate.'));
202
+ return;
203
+ }
204
+ const user = this.getUser();
205
+ if (user) {
206
+ console.log(chalk_1.default.cyan('Current user:'));
207
+ console.log(` UID: ${user.uid}`);
208
+ if (user.email) {
209
+ console.log(` Email: ${user.email}`);
210
+ }
211
+ if (user.displayName) {
212
+ console.log(` Name: ${user.displayName}`);
213
+ }
214
+ }
215
+ }
216
+ }
217
+ exports.FirebaseAuthClient = FirebaseAuthClient;
218
+ //# sourceMappingURL=firebase-auth-simple.js.map