paean 0.1.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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +296 -0
  3. package/dist/api/auth.d.ts +71 -0
  4. package/dist/api/auth.d.ts.map +1 -0
  5. package/dist/api/auth.js +257 -0
  6. package/dist/api/auth.js.map +1 -0
  7. package/dist/api/client.d.ts +37 -0
  8. package/dist/api/client.d.ts.map +1 -0
  9. package/dist/api/client.js +101 -0
  10. package/dist/api/client.js.map +1 -0
  11. package/dist/api/todo.d.ts +167 -0
  12. package/dist/api/todo.d.ts.map +1 -0
  13. package/dist/api/todo.js +137 -0
  14. package/dist/api/todo.js.map +1 -0
  15. package/dist/cli.d.ts +7 -0
  16. package/dist/cli.d.ts.map +1 -0
  17. package/dist/cli.js +36 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/commands/context.d.ts +7 -0
  20. package/dist/commands/context.d.ts.map +1 -0
  21. package/dist/commands/context.js +155 -0
  22. package/dist/commands/context.js.map +1 -0
  23. package/dist/commands/login.d.ts +7 -0
  24. package/dist/commands/login.d.ts.map +1 -0
  25. package/dist/commands/login.js +108 -0
  26. package/dist/commands/login.js.map +1 -0
  27. package/dist/commands/logout.d.ts +7 -0
  28. package/dist/commands/logout.d.ts.map +1 -0
  29. package/dist/commands/logout.js +27 -0
  30. package/dist/commands/logout.js.map +1 -0
  31. package/dist/commands/serve.d.ts +7 -0
  32. package/dist/commands/serve.d.ts.map +1 -0
  33. package/dist/commands/serve.js +29 -0
  34. package/dist/commands/serve.js.map +1 -0
  35. package/dist/commands/tasks.d.ts +7 -0
  36. package/dist/commands/tasks.d.ts.map +1 -0
  37. package/dist/commands/tasks.js +276 -0
  38. package/dist/commands/tasks.js.map +1 -0
  39. package/dist/commands/validate.d.ts +7 -0
  40. package/dist/commands/validate.d.ts.map +1 -0
  41. package/dist/commands/validate.js +123 -0
  42. package/dist/commands/validate.js.map +1 -0
  43. package/dist/index.d.ts +13 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +19 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/mcp/resources.d.ts +14 -0
  48. package/dist/mcp/resources.d.ts.map +1 -0
  49. package/dist/mcp/resources.js +166 -0
  50. package/dist/mcp/resources.js.map +1 -0
  51. package/dist/mcp/server.d.ts +12 -0
  52. package/dist/mcp/server.d.ts.map +1 -0
  53. package/dist/mcp/server.js +82 -0
  54. package/dist/mcp/server.js.map +1 -0
  55. package/dist/mcp/tools.d.ts +14 -0
  56. package/dist/mcp/tools.d.ts.map +1 -0
  57. package/dist/mcp/tools.js +341 -0
  58. package/dist/mcp/tools.js.map +1 -0
  59. package/dist/utils/config.d.ts +69 -0
  60. package/dist/utils/config.d.ts.map +1 -0
  61. package/dist/utils/config.js +129 -0
  62. package/dist/utils/config.js.map +1 -0
  63. package/dist/utils/output.d.ts +79 -0
  64. package/dist/utils/output.d.ts.map +1 -0
  65. package/dist/utils/output.js +157 -0
  66. package/dist/utils/output.js.map +1 -0
  67. package/dist/utils/project.d.ts +29 -0
  68. package/dist/utils/project.d.ts.map +1 -0
  69. package/dist/utils/project.js +135 -0
  70. package/dist/utils/project.js.map +1 -0
  71. package/package.json +72 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Paean AI (Zero One Intelligence)
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,296 @@
1
+ # Paean CLI
2
+
3
+ > Connect your local development environment with Paean AI cloud for intelligent task management and AI agent workflows.
4
+
5
+ **Paean CLI** is a dual-mode command-line tool that serves both as:
6
+ - A **human-friendly CLI** for developers to manage tasks and authenticate
7
+ - An **MCP (Model Context Protocol) server** for AI agent integration with Cursor, Claude Code, and other AI coding assistants
8
+
9
+ ## Features
10
+
11
+ - **Task Management**: View, create, complete, and manage tasks from the command line
12
+ - **MCP Server Mode**: Seamless integration with AI coding assistants via MCP protocol
13
+ - **Dual Authentication**: Support for both QR code login and browser-based OAuth
14
+ - **Context Generation**: Generate context files for AI agents with current task information
15
+ - **Project Detection**: Automatically detects project type and associates tasks
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ # Install globally via npm
21
+ npm install -g paean
22
+
23
+ # Or use directly with npx
24
+ npx paean --help
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Authenticate
30
+
31
+ ```bash
32
+ # Browser-based login (recommended)
33
+ paean login
34
+
35
+ # QR code login (scan with Paean mobile app)
36
+ paean login --qr
37
+ ```
38
+
39
+ ### 2. View Tasks
40
+
41
+ ```bash
42
+ # List all tasks
43
+ paean tasks
44
+
45
+ # List pending tasks only
46
+ paean tasks --status pending
47
+
48
+ # Output as JSON
49
+ paean tasks --json
50
+ ```
51
+
52
+ ### 3. Manage Tasks
53
+
54
+ ```bash
55
+ # Create a new task
56
+ paean tasks add "Implement user authentication"
57
+
58
+ # Complete a task
59
+ paean tasks complete <task-id> --summary "Added JWT authentication"
60
+
61
+ # Update task priority
62
+ paean tasks update <task-id> --priority high
63
+ ```
64
+
65
+ ### 4. Generate Context for AI
66
+
67
+ ```bash
68
+ # Generate context file
69
+ paean context
70
+
71
+ # Output to stdout
72
+ paean context --stdout
73
+
74
+ # Output as JSON
75
+ paean context --json
76
+ ```
77
+
78
+ ## MCP Server Mode
79
+
80
+ Paean CLI can run as an MCP server, allowing AI coding assistants to read tasks and update their status.
81
+
82
+ ### Configure in Cursor
83
+
84
+ Add to your `.cursor/mcp.json`:
85
+
86
+ ```json
87
+ {
88
+ "mcpServers": {
89
+ "paean": {
90
+ "command": "npx",
91
+ "args": ["paean", "serve"]
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### Configure in Claude Desktop
98
+
99
+ Add to your Claude Desktop config:
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "paean": {
105
+ "command": "npx",
106
+ "args": ["paean", "serve"]
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ### Available MCP Resources
113
+
114
+ | Resource URI | Description |
115
+ |-------------|-------------|
116
+ | `paean://tasks/pending` | Current pending tasks |
117
+ | `paean://tasks/completed` | Recently completed tasks |
118
+ | `paean://tasks/all` | All tasks with full details |
119
+ | `paean://context` | Full project context |
120
+ | `paean://pending-changes` | AI-suggested changes awaiting review |
121
+
122
+ ### Available MCP Tools
123
+
124
+ | Tool | Description |
125
+ |------|-------------|
126
+ | `paean_complete_task` | Mark a task as completed |
127
+ | `paean_create_task` | Create a new task |
128
+ | `paean_update_task` | Update task status/priority |
129
+ | `paean_list_tasks` | List tasks with filters |
130
+ | `paean_accept_change` | Accept an AI-suggested change |
131
+ | `paean_reject_change` | Reject an AI-suggested change |
132
+
133
+ ## Commands Reference
134
+
135
+ ### `paean login`
136
+
137
+ Authenticate with Paean AI.
138
+
139
+ ```bash
140
+ paean login # Browser-based login
141
+ paean login --qr # QR code login
142
+ paean login --check # Check current auth status
143
+ ```
144
+
145
+ ### `paean logout`
146
+
147
+ Sign out and clear stored credentials.
148
+
149
+ ```bash
150
+ paean logout
151
+ paean logout --force # Skip confirmation
152
+ ```
153
+
154
+ ### `paean tasks`
155
+
156
+ View and manage tasks.
157
+
158
+ ```bash
159
+ paean tasks # List all tasks
160
+ paean tasks --status pending # Filter by status
161
+ paean tasks --priority high # Filter by priority
162
+ paean tasks --json # JSON output
163
+
164
+ paean tasks add "Task description" # Create task
165
+ paean tasks complete <id> # Complete task
166
+ paean tasks update <id> # Update task
167
+ paean tasks delete <id> # Delete task
168
+
169
+ paean tasks pending # View AI-suggested changes
170
+ paean tasks accept <changeId> # Accept change
171
+ paean tasks reject <changeId> # Reject change
172
+ ```
173
+
174
+ ### `paean context`
175
+
176
+ Generate context file for AI agents.
177
+
178
+ ```bash
179
+ paean context # Write to .paean/context.md
180
+ paean context --output custom.md # Custom output path
181
+ paean context --json # JSON format
182
+ paean context --stdout # Print to stdout
183
+ ```
184
+
185
+ ### `paean serve`
186
+
187
+ Start MCP server for AI agent integration.
188
+
189
+ ```bash
190
+ paean serve # Start MCP server (stdio)
191
+ paean serve --debug # Enable debug logging
192
+ ```
193
+
194
+ ### `paean validate`
195
+
196
+ Check if current changes satisfy pending tasks.
197
+
198
+ ```bash
199
+ paean validate # Validate pending tasks
200
+ paean validate --auto-complete # Auto-complete validated tasks
201
+ paean validate --json # JSON output
202
+ ```
203
+
204
+ ## Configuration
205
+
206
+ Configuration is stored in `~/.paean/config.json`:
207
+
208
+ ```json
209
+ {
210
+ "token": "your-jwt-token",
211
+ "email": "user@example.com",
212
+ "apiUrl": "https://api.paean.ai",
213
+ "webUrl": "https://m.paean.ai",
214
+ "defaultPriority": "medium",
215
+ "outputFormat": "table"
216
+ }
217
+ ```
218
+
219
+ View config path:
220
+ ```bash
221
+ paean --config
222
+ ```
223
+
224
+ ## Programmatic Usage
225
+
226
+ Paean CLI can also be used as a library:
227
+
228
+ ```typescript
229
+ import {
230
+ qrLogin,
231
+ browserLogin,
232
+ getTodoList,
233
+ completeTodoItem,
234
+ startMcpServer,
235
+ } from 'paean';
236
+
237
+ // Authenticate
238
+ const result = await browserLogin();
239
+ if (result.success) {
240
+ // Get tasks
241
+ const tasks = await getTodoList({ status: 'pending' });
242
+ console.log(tasks.data.items);
243
+
244
+ // Complete a task
245
+ await completeTodoItem('task-id', 'Completed the feature');
246
+ }
247
+ ```
248
+
249
+ ## A2A Workflow
250
+
251
+ Paean CLI enables an Agent-to-Agent (A2A) workflow:
252
+
253
+ 1. **Manager (Paean AI Cloud)**: Creates and organizes tasks based on business requirements
254
+ 2. **Worker (Claude/Cursor)**: Reads tasks via MCP, implements changes, reports completion
255
+ 3. **Reviewer (Human)**: Reviews AI suggestions and approves changes
256
+
257
+ ```
258
+ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
259
+ │ Paean AI │────▶│ Paean CLI │────▶│ Cursor/Claude │
260
+ │ (Manager) │ │ (MCP Bridge) │ │ (Worker) │
261
+ └─────────────────┘ └─────────────────┘ └─────────────────┘
262
+ │ │ │
263
+ │ Create tasks │ Read via MCP │
264
+ │ │ Complete tasks │
265
+ ▼ ▼ ▼
266
+ ┌─────────────────────────────────────────────────────────────────┐
267
+ │ Human (Reviewer) │
268
+ │ Reviews changes, accepts/rejects suggestions │
269
+ └─────────────────────────────────────────────────────────────────┘
270
+ ```
271
+
272
+ ## Security
273
+
274
+ - **Local Storage**: Credentials are stored locally in `~/.paean/`
275
+ - **Localhost Only**: Browser OAuth callbacks only accept localhost URLs
276
+ - **Token-Based**: Uses JWT tokens that expire and can be revoked
277
+ - **No Password Storage**: Passwords are never stored locally
278
+
279
+ ## Requirements
280
+
281
+ - Node.js 18.0.0 or higher
282
+ - npm or yarn
283
+
284
+ ## Contributing
285
+
286
+ Contributions are welcome! Please see our contributing guidelines.
287
+
288
+ ## License
289
+
290
+ MIT License - see LICENSE file for details.
291
+
292
+ ## Links
293
+
294
+ - **Website**: https://paean.ai
295
+ - **API Documentation**: https://api.paean.ai/docs
296
+ - **Support**: support@paean.ai
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Authentication API
3
+ * Handles QR code login and browser OAuth flows
4
+ */
5
+ export interface QrSessionResponse {
6
+ success: boolean;
7
+ sessionId: string;
8
+ expiresAt: string;
9
+ expiresInSeconds: number;
10
+ qrContent: string;
11
+ }
12
+ export interface QrStatusResponse {
13
+ success: boolean;
14
+ status: 'pending' | 'scanned' | 'confirmed' | 'expired' | 'used';
15
+ token?: string;
16
+ userId?: number;
17
+ isExpired?: boolean;
18
+ expiresAt?: string;
19
+ }
20
+ export interface LoginResponse {
21
+ user: {
22
+ id: number;
23
+ email: string;
24
+ username?: string;
25
+ displayName?: string;
26
+ };
27
+ token: string;
28
+ }
29
+ export interface UserInfo {
30
+ id: number;
31
+ email: string;
32
+ name?: string;
33
+ picture?: string;
34
+ }
35
+ /**
36
+ * Create a QR login session
37
+ */
38
+ export declare function createQrSession(deviceType?: string): Promise<QrSessionResponse>;
39
+ /**
40
+ * Check QR session status
41
+ */
42
+ export declare function getQrSessionStatus(sessionId: string): Promise<QrStatusResponse>;
43
+ /**
44
+ * Perform QR code login
45
+ * Displays QR code in terminal and polls for confirmation
46
+ */
47
+ export declare function qrLogin(onStatus?: (status: string) => void): Promise<{
48
+ success: boolean;
49
+ error?: string;
50
+ }>;
51
+ /**
52
+ * Perform browser-based OAuth login
53
+ * Opens browser and starts local server to receive callback
54
+ */
55
+ export declare function browserLogin(): Promise<{
56
+ success: boolean;
57
+ error?: string;
58
+ }>;
59
+ /**
60
+ * Get current user info
61
+ */
62
+ export declare function getCurrentUser(): Promise<UserInfo | null>;
63
+ /**
64
+ * Validate current token
65
+ */
66
+ export declare function validateToken(): Promise<boolean>;
67
+ /**
68
+ * Logout - clear stored credentials
69
+ */
70
+ export declare function logout(): void;
71
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAUH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,MAAM,CAAC;IACjE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,SAAQ,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAOpF;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAIrF;AAED;;;GAGG;AACH,wBAAsB,OAAO,CAC3B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,GAClC,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiF/C;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA2HlF;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAc/D;AAED;;GAEG;AACH,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAOtD;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,IAAI,CAG7B"}
@@ -0,0 +1,257 @@
1
+ /**
2
+ * Authentication API
3
+ * Handles QR code login and browser OAuth flows
4
+ */
5
+ import { createServer } from 'http';
6
+ import { URL } from 'url';
7
+ import open from 'open';
8
+ import qrcode from 'qrcode-terminal';
9
+ import { getPublicApiClient, getApiClient, resetApiClients } from './client.js';
10
+ import { storeAuth, clearAuth, getWebUrl } from '../utils/config.js';
11
+ import * as output from '../utils/output.js';
12
+ /**
13
+ * Create a QR login session
14
+ */
15
+ export async function createQrSession(deviceType = 'CLI') {
16
+ const client = getPublicApiClient();
17
+ const response = await client.post('/auth/qr/create-session', {
18
+ deviceType,
19
+ deviceId: `cli-${Date.now()}`,
20
+ });
21
+ return response.data;
22
+ }
23
+ /**
24
+ * Check QR session status
25
+ */
26
+ export async function getQrSessionStatus(sessionId) {
27
+ const client = getPublicApiClient();
28
+ const response = await client.get(`/auth/qr/status/${sessionId}`);
29
+ return response.data;
30
+ }
31
+ /**
32
+ * Perform QR code login
33
+ * Displays QR code in terminal and polls for confirmation
34
+ */
35
+ export async function qrLogin(onStatus) {
36
+ try {
37
+ // Create QR session
38
+ const session = await createQrSession();
39
+ // Display QR code in terminal
40
+ output.newline();
41
+ output.info('Scan this QR code with the Paean mobile app to log in:');
42
+ output.newline();
43
+ qrcode.generate(session.qrContent, { small: true });
44
+ output.newline();
45
+ output.dim(`Session expires in ${Math.floor(session.expiresInSeconds / 60)} minutes`);
46
+ output.newline();
47
+ // Poll for status
48
+ const maxPollTime = session.expiresInSeconds * 1000;
49
+ const pollInterval = 2000;
50
+ const startTime = Date.now();
51
+ while (Date.now() - startTime < maxPollTime) {
52
+ const status = await getQrSessionStatus(session.sessionId);
53
+ if (onStatus) {
54
+ onStatus(status.status);
55
+ }
56
+ switch (status.status) {
57
+ case 'scanned':
58
+ output.info('QR code scanned! Waiting for confirmation...');
59
+ break;
60
+ case 'confirmed':
61
+ if (status.token && status.userId) {
62
+ // Store authentication
63
+ storeAuth({
64
+ token: status.token,
65
+ userId: status.userId,
66
+ });
67
+ resetApiClients();
68
+ // Try to fetch user info
69
+ try {
70
+ const userInfo = await getCurrentUser();
71
+ if (userInfo) {
72
+ storeAuth({
73
+ token: status.token,
74
+ userId: status.userId,
75
+ email: userInfo.email,
76
+ });
77
+ }
78
+ }
79
+ catch {
80
+ // Ignore - we still have the token
81
+ }
82
+ return { success: true };
83
+ }
84
+ return { success: false, error: 'No token received' };
85
+ case 'expired':
86
+ return { success: false, error: 'QR code expired. Please try again.' };
87
+ case 'used':
88
+ return { success: false, error: 'This QR code has already been used.' };
89
+ case 'pending':
90
+ default:
91
+ // Continue polling
92
+ break;
93
+ }
94
+ // Wait before next poll
95
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
96
+ }
97
+ return { success: false, error: 'Login timed out. Please try again.' };
98
+ }
99
+ catch (error) {
100
+ const message = error instanceof Error ? error.message : 'Unknown error';
101
+ return { success: false, error: message };
102
+ }
103
+ }
104
+ /**
105
+ * Perform browser-based OAuth login
106
+ * Opens browser and starts local server to receive callback
107
+ */
108
+ export async function browserLogin() {
109
+ return new Promise((resolve) => {
110
+ // Find an available port
111
+ const port = 9876 + Math.floor(Math.random() * 100);
112
+ const callbackUrl = `http://localhost:${port}/callback`;
113
+ let server = null;
114
+ let timeoutId = null;
115
+ const cleanup = () => {
116
+ if (timeoutId) {
117
+ clearTimeout(timeoutId);
118
+ timeoutId = null;
119
+ }
120
+ if (server) {
121
+ server.close();
122
+ server = null;
123
+ }
124
+ };
125
+ // Create local server to receive callback
126
+ server = createServer((req, res) => {
127
+ const url = new URL(req.url || '/', `http://localhost:${port}`);
128
+ if (url.pathname === '/callback') {
129
+ const token = url.searchParams.get('token');
130
+ const error = url.searchParams.get('error');
131
+ const userId = url.searchParams.get('userId');
132
+ const email = url.searchParams.get('email');
133
+ // Send response to browser
134
+ res.writeHead(200, { 'Content-Type': 'text/html' });
135
+ if (token) {
136
+ res.end(`
137
+ <!DOCTYPE html>
138
+ <html>
139
+ <head>
140
+ <title>Login Successful</title>
141
+ <style>
142
+ body { font-family: system-ui; text-align: center; padding: 50px; background: #0a0a0a; color: #fff; }
143
+ .success { color: #22c55e; font-size: 48px; }
144
+ h1 { color: #06b6d4; }
145
+ </style>
146
+ </head>
147
+ <body>
148
+ <div class="success">✓</div>
149
+ <h1>Login Successful!</h1>
150
+ <p>You can close this window and return to the terminal.</p>
151
+ </body>
152
+ </html>
153
+ `);
154
+ // Store authentication
155
+ storeAuth({
156
+ token,
157
+ userId: userId ? parseInt(userId, 10) : undefined,
158
+ email: email || undefined,
159
+ });
160
+ resetApiClients();
161
+ cleanup();
162
+ resolve({ success: true });
163
+ }
164
+ else {
165
+ res.end(`
166
+ <!DOCTYPE html>
167
+ <html>
168
+ <head>
169
+ <title>Login Failed</title>
170
+ <style>
171
+ body { font-family: system-ui; text-align: center; padding: 50px; background: #0a0a0a; color: #fff; }
172
+ .error { color: #ef4444; font-size: 48px; }
173
+ h1 { color: #ef4444; }
174
+ </style>
175
+ </head>
176
+ <body>
177
+ <div class="error">✗</div>
178
+ <h1>Login Failed</h1>
179
+ <p>${error || 'An error occurred during login.'}</p>
180
+ <p>Please return to the terminal and try again.</p>
181
+ </body>
182
+ </html>
183
+ `);
184
+ cleanup();
185
+ resolve({ success: false, error: error || 'Login failed' });
186
+ }
187
+ }
188
+ else {
189
+ res.writeHead(404);
190
+ res.end('Not found');
191
+ }
192
+ });
193
+ server.on('error', (err) => {
194
+ cleanup();
195
+ resolve({ success: false, error: `Server error: ${err.message}` });
196
+ });
197
+ server.listen(port, async () => {
198
+ // Open browser to login page
199
+ const webUrl = getWebUrl();
200
+ const loginUrl = `${webUrl}/auth/cli?callback=${encodeURIComponent(callbackUrl)}`;
201
+ output.info('Opening browser for login...');
202
+ output.dim(`If browser doesn't open, visit: ${loginUrl}`);
203
+ output.newline();
204
+ try {
205
+ await open(loginUrl);
206
+ }
207
+ catch {
208
+ output.warning('Could not open browser automatically.');
209
+ output.info(`Please open this URL manually: ${loginUrl}`);
210
+ }
211
+ output.info('Waiting for login...');
212
+ // Set timeout (5 minutes)
213
+ timeoutId = setTimeout(() => {
214
+ cleanup();
215
+ resolve({ success: false, error: 'Login timed out. Please try again.' });
216
+ }, 5 * 60 * 1000);
217
+ });
218
+ });
219
+ }
220
+ /**
221
+ * Get current user info
222
+ */
223
+ export async function getCurrentUser() {
224
+ try {
225
+ const client = getApiClient();
226
+ const response = await client.get('/user/profile');
227
+ // Handle both response formats
228
+ const data = response.data;
229
+ if ('user' in data) {
230
+ return data.user;
231
+ }
232
+ return data;
233
+ }
234
+ catch {
235
+ return null;
236
+ }
237
+ }
238
+ /**
239
+ * Validate current token
240
+ */
241
+ export async function validateToken() {
242
+ try {
243
+ const user = await getCurrentUser();
244
+ return user !== null;
245
+ }
246
+ catch {
247
+ return false;
248
+ }
249
+ }
250
+ /**
251
+ * Logout - clear stored credentials
252
+ */
253
+ export function logout() {
254
+ clearAuth();
255
+ resetApiClients();
256
+ }
257
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}