@pollychrome/joan-mcp 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 (83) hide show
  1. package/README.md +385 -0
  2. package/bin/joan-mcp +16 -0
  3. package/dist/auth.d.ts +49 -0
  4. package/dist/auth.d.ts.map +1 -0
  5. package/dist/auth.js +264 -0
  6. package/dist/auth.js.map +1 -0
  7. package/dist/cli.d.ts +7 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +326 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/client/api-client.d.ts +86 -0
  12. package/dist/client/api-client.d.ts.map +1 -0
  13. package/dist/client/api-client.js +182 -0
  14. package/dist/client/api-client.js.map +1 -0
  15. package/dist/client/types.d.ts +270 -0
  16. package/dist/client/types.d.ts.map +1 -0
  17. package/dist/client/types.js +5 -0
  18. package/dist/client/types.js.map +1 -0
  19. package/dist/config.d.ts +33 -0
  20. package/dist/config.d.ts.map +1 -0
  21. package/dist/config.js +71 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/index.d.ts +14 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +118 -0
  26. package/dist/index.js.map +1 -0
  27. package/dist/resources/goals.d.ts +7 -0
  28. package/dist/resources/goals.d.ts.map +1 -0
  29. package/dist/resources/goals.js +49 -0
  30. package/dist/resources/goals.js.map +1 -0
  31. package/dist/resources/index.d.ts +16 -0
  32. package/dist/resources/index.d.ts.map +1 -0
  33. package/dist/resources/index.js +20 -0
  34. package/dist/resources/index.js.map +1 -0
  35. package/dist/resources/milestones.d.ts +7 -0
  36. package/dist/resources/milestones.d.ts.map +1 -0
  37. package/dist/resources/milestones.js +40 -0
  38. package/dist/resources/milestones.js.map +1 -0
  39. package/dist/resources/notes.d.ts +7 -0
  40. package/dist/resources/notes.d.ts.map +1 -0
  41. package/dist/resources/notes.js +33 -0
  42. package/dist/resources/notes.js.map +1 -0
  43. package/dist/resources/projects.d.ts +7 -0
  44. package/dist/resources/projects.d.ts.map +1 -0
  45. package/dist/resources/projects.js +97 -0
  46. package/dist/resources/projects.js.map +1 -0
  47. package/dist/resources/tasks.d.ts +7 -0
  48. package/dist/resources/tasks.d.ts.map +1 -0
  49. package/dist/resources/tasks.js +36 -0
  50. package/dist/resources/tasks.js.map +1 -0
  51. package/dist/tools/goals.d.ts +7 -0
  52. package/dist/tools/goals.d.ts.map +1 -0
  53. package/dist/tools/goals.js +114 -0
  54. package/dist/tools/goals.js.map +1 -0
  55. package/dist/tools/index.d.ts +16 -0
  56. package/dist/tools/index.d.ts.map +1 -0
  57. package/dist/tools/index.js +20 -0
  58. package/dist/tools/index.js.map +1 -0
  59. package/dist/tools/milestones.d.ts +7 -0
  60. package/dist/tools/milestones.d.ts.map +1 -0
  61. package/dist/tools/milestones.js +119 -0
  62. package/dist/tools/milestones.js.map +1 -0
  63. package/dist/tools/notes.d.ts +7 -0
  64. package/dist/tools/notes.d.ts.map +1 -0
  65. package/dist/tools/notes.js +82 -0
  66. package/dist/tools/notes.js.map +1 -0
  67. package/dist/tools/projects.d.ts +7 -0
  68. package/dist/tools/projects.d.ts.map +1 -0
  69. package/dist/tools/projects.js +63 -0
  70. package/dist/tools/projects.js.map +1 -0
  71. package/dist/tools/tasks.d.ts +7 -0
  72. package/dist/tools/tasks.d.ts.map +1 -0
  73. package/dist/tools/tasks.js +125 -0
  74. package/dist/tools/tasks.js.map +1 -0
  75. package/dist/utils/converters.d.ts +78 -0
  76. package/dist/utils/converters.d.ts.map +1 -0
  77. package/dist/utils/converters.js +79 -0
  78. package/dist/utils/converters.js.map +1 -0
  79. package/dist/utils/errors.d.ts +27 -0
  80. package/dist/utils/errors.d.ts.map +1 -0
  81. package/dist/utils/errors.js +104 -0
  82. package/dist/utils/errors.js.map +1 -0
  83. package/package.json +53 -0
package/dist/auth.js ADDED
@@ -0,0 +1,264 @@
1
+ /**
2
+ * Auth token management for Joan MCP server
3
+ * Handles storing, retrieving, and validating auth tokens
4
+ */
5
+ import { createServer } from 'node:http';
6
+ import { mkdir, readFile, writeFile, unlink, chmod } from 'node:fs/promises';
7
+ import { homedir } from 'node:os';
8
+ import { join } from 'node:path';
9
+ import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto';
10
+ import { AuthenticationError } from './utils/errors.js';
11
+ const CONFIG_DIR = join(homedir(), '.joan-mcp');
12
+ const CREDENTIALS_FILE = join(CONFIG_DIR, 'credentials.json');
13
+ const ALGORITHM = 'aes-256-gcm';
14
+ /**
15
+ * Get a machine-specific encryption key
16
+ * Uses a combination of factors to create a stable key
17
+ */
18
+ function getMachineKey() {
19
+ // Use home directory and username as salt - stable across sessions
20
+ const salt = `${homedir()}-${process.env.USER || process.env.USERNAME || 'joan'}`;
21
+ return scryptSync('joan-mcp-local-encryption', salt, 32);
22
+ }
23
+ /**
24
+ * Encrypt a token for storage
25
+ */
26
+ function encryptToken(token) {
27
+ const key = getMachineKey();
28
+ const iv = randomBytes(16);
29
+ const cipher = createCipheriv(ALGORITHM, key, iv);
30
+ let encrypted = cipher.update(token, 'utf8', 'hex');
31
+ encrypted += cipher.final('hex');
32
+ const authTag = cipher.getAuthTag();
33
+ return {
34
+ encrypted,
35
+ iv: iv.toString('hex'),
36
+ authTag: authTag.toString('hex'),
37
+ };
38
+ }
39
+ /**
40
+ * Decrypt a stored token
41
+ */
42
+ function decryptToken(encrypted, iv, authTag) {
43
+ const key = getMachineKey();
44
+ const decipher = createDecipheriv(ALGORITHM, key, Buffer.from(iv, 'hex'));
45
+ decipher.setAuthTag(Buffer.from(authTag, 'hex'));
46
+ let decrypted = decipher.update(encrypted, 'hex', 'utf8');
47
+ decrypted += decipher.final('utf8');
48
+ return decrypted;
49
+ }
50
+ /**
51
+ * Ensure the config directory exists
52
+ */
53
+ async function ensureConfigDir() {
54
+ try {
55
+ await mkdir(CONFIG_DIR, { recursive: true, mode: 0o700 });
56
+ }
57
+ catch (error) {
58
+ if (error.code !== 'EEXIST') {
59
+ throw error;
60
+ }
61
+ }
62
+ }
63
+ /**
64
+ * Store auth token securely
65
+ */
66
+ export async function storeToken(token, email, expiresAt) {
67
+ await ensureConfigDir();
68
+ const { encrypted, iv, authTag } = encryptToken(token);
69
+ const credentials = {
70
+ token: encrypted,
71
+ iv,
72
+ authTag,
73
+ email,
74
+ expiresAt: expiresAt?.toISOString(),
75
+ createdAt: new Date().toISOString(),
76
+ };
77
+ await writeFile(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), 'utf8');
78
+ await chmod(CREDENTIALS_FILE, 0o600); // Owner read/write only
79
+ }
80
+ /**
81
+ * Retrieve stored auth token
82
+ */
83
+ export async function getStoredToken() {
84
+ try {
85
+ const content = await readFile(CREDENTIALS_FILE, 'utf8');
86
+ const credentials = JSON.parse(content);
87
+ // Check if token is expired
88
+ if (credentials.expiresAt) {
89
+ const expiresAt = new Date(credentials.expiresAt);
90
+ if (expiresAt < new Date()) {
91
+ // Token expired, remove it
92
+ await clearToken();
93
+ return null;
94
+ }
95
+ }
96
+ const token = decryptToken(credentials.token, credentials.iv, credentials.authTag);
97
+ return {
98
+ token,
99
+ email: credentials.email,
100
+ expiresAt: credentials.expiresAt ? new Date(credentials.expiresAt) : undefined,
101
+ };
102
+ }
103
+ catch (error) {
104
+ if (error.code === 'ENOENT') {
105
+ return null;
106
+ }
107
+ throw error;
108
+ }
109
+ }
110
+ /**
111
+ * Clear stored token
112
+ */
113
+ export async function clearToken() {
114
+ try {
115
+ await unlink(CREDENTIALS_FILE);
116
+ }
117
+ catch (error) {
118
+ if (error.code !== 'ENOENT') {
119
+ throw error;
120
+ }
121
+ }
122
+ }
123
+ /**
124
+ * Get auth token from stored credentials or environment variable
125
+ */
126
+ export async function getAuthToken() {
127
+ // First, check environment variable
128
+ if (process.env.JOAN_AUTH_TOKEN) {
129
+ return process.env.JOAN_AUTH_TOKEN;
130
+ }
131
+ // Then, check stored credentials
132
+ const stored = await getStoredToken();
133
+ if (stored) {
134
+ return stored.token;
135
+ }
136
+ throw new AuthenticationError('No authentication token found. Run "joan-mcp login" to authenticate or set JOAN_AUTH_TOKEN environment variable.');
137
+ }
138
+ /**
139
+ * Parse JWT to extract payload (without verification)
140
+ */
141
+ export function parseJwt(token) {
142
+ try {
143
+ const parts = token.split('.');
144
+ if (parts.length !== 3) {
145
+ return null;
146
+ }
147
+ const payload = JSON.parse(Buffer.from(parts[1], 'base64').toString('utf8'));
148
+ return payload;
149
+ }
150
+ catch {
151
+ return null;
152
+ }
153
+ }
154
+ /**
155
+ * Check if token is expired based on JWT payload
156
+ */
157
+ export function isTokenExpired(token) {
158
+ const payload = parseJwt(token);
159
+ if (!payload?.exp) {
160
+ return false; // Assume not expired if no exp claim
161
+ }
162
+ return payload.exp * 1000 < Date.now();
163
+ }
164
+ /**
165
+ * Start local HTTP server for OAuth callback
166
+ * Returns a promise that resolves with the token when received
167
+ */
168
+ export function startCallbackServer(port) {
169
+ return new Promise((resolve, reject) => {
170
+ const server = createServer((req, res) => {
171
+ const url = new URL(req.url || '/', `http://localhost:${port}`);
172
+ if (url.pathname === '/callback') {
173
+ const token = url.searchParams.get('token');
174
+ const email = url.searchParams.get('email');
175
+ const error = url.searchParams.get('error');
176
+ if (error) {
177
+ res.writeHead(400, { 'Content-Type': 'text/html' });
178
+ res.end(`
179
+ <!DOCTYPE html>
180
+ <html>
181
+ <head><title>Authentication Failed</title></head>
182
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
183
+ <h1 style="color: #dc2626;">Authentication Failed</h1>
184
+ <p>${error}</p>
185
+ <p>You can close this window.</p>
186
+ </body>
187
+ </html>
188
+ `);
189
+ server.close();
190
+ reject(new AuthenticationError(error));
191
+ return;
192
+ }
193
+ if (!token) {
194
+ res.writeHead(400, { 'Content-Type': 'text/html' });
195
+ res.end(`
196
+ <!DOCTYPE html>
197
+ <html>
198
+ <head><title>Authentication Failed</title></head>
199
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
200
+ <h1 style="color: #dc2626;">Authentication Failed</h1>
201
+ <p>No token received.</p>
202
+ <p>You can close this window.</p>
203
+ </body>
204
+ </html>
205
+ `);
206
+ server.close();
207
+ reject(new AuthenticationError('No token received'));
208
+ return;
209
+ }
210
+ res.writeHead(200, { 'Content-Type': 'text/html' });
211
+ res.end(`
212
+ <!DOCTYPE html>
213
+ <html>
214
+ <head><title>Authentication Successful</title></head>
215
+ <body style="font-family: system-ui; padding: 40px; text-align: center;">
216
+ <h1 style="color: #16a34a;">Authentication Successful!</h1>
217
+ <p>You are now logged in to Joan MCP.</p>
218
+ <p>You can close this window and return to the terminal.</p>
219
+ <script>setTimeout(() => window.close(), 2000);</script>
220
+ </body>
221
+ </html>
222
+ `);
223
+ server.close();
224
+ resolve({ token, email: email || undefined });
225
+ }
226
+ else {
227
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
228
+ res.end('Not found');
229
+ }
230
+ });
231
+ server.on('error', reject);
232
+ server.listen(port, 'localhost', () => {
233
+ // Server started
234
+ });
235
+ // Timeout after 5 minutes
236
+ setTimeout(() => {
237
+ server.close();
238
+ reject(new AuthenticationError('Authentication timeout - no response received'));
239
+ }, 5 * 60 * 1000);
240
+ });
241
+ }
242
+ /**
243
+ * Find an available port for the callback server
244
+ */
245
+ export async function findAvailablePort(startPort = 9876) {
246
+ return new Promise((resolve, reject) => {
247
+ const server = createServer();
248
+ server.listen(startPort, 'localhost', () => {
249
+ const address = server.address();
250
+ const port = typeof address === 'object' && address ? address.port : startPort;
251
+ server.close(() => resolve(port));
252
+ });
253
+ server.on('error', (err) => {
254
+ if (err.code === 'EADDRINUSE') {
255
+ // Try next port
256
+ findAvailablePort(startPort + 1).then(resolve).catch(reject);
257
+ }
258
+ else {
259
+ reject(err);
260
+ }
261
+ });
262
+ });
263
+ }
264
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for Joan MCP server
4
+ * Commands: login, logout, status, serve (default)
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;GAGG"}
package/dist/cli.js ADDED
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * CLI for Joan MCP server
4
+ * Commands: login, logout, status, serve (default)
5
+ */
6
+ import { spawn } from 'node:child_process';
7
+ import { getStoredToken, storeToken, clearToken, findAvailablePort, startCallbackServer, parseJwt, isTokenExpired, } from './auth.js';
8
+ import { getApiUrl, getMcpAuthUrl, loadConfig } from './config.js';
9
+ import { JoanApiClient } from './client/api-client.js';
10
+ import { startServer } from './index.js';
11
+ const HELP_TEXT = `
12
+ Joan MCP Server - AI assistant integration for Joan productivity app
13
+
14
+ Usage: joan-mcp <command>
15
+
16
+ Commands:
17
+ init Set up Joan MCP (login + configure Claude Code)
18
+ serve Start the MCP server (default)
19
+ login Authenticate with Joan
20
+ logout Clear stored credentials
21
+ status Show current authentication status
22
+ help Show this help message
23
+
24
+ Examples:
25
+ joan-mcp init # First-time setup (recommended)
26
+ joan-mcp login # Opens browser to authenticate
27
+ joan-mcp status # Shows if logged in
28
+ joan-mcp serve # Start MCP server
29
+ joan-mcp # Same as 'joan-mcp serve'
30
+
31
+ Environment Variables:
32
+ JOAN_AUTH_TOKEN JWT token for authentication (alternative to login)
33
+ JOAN_API_URL API base URL (default: production)
34
+ `;
35
+ /**
36
+ * Open a URL in the default browser
37
+ */
38
+ async function openBrowser(url) {
39
+ const platform = process.platform;
40
+ let command;
41
+ let args;
42
+ switch (platform) {
43
+ case 'darwin':
44
+ command = 'open';
45
+ args = [url];
46
+ break;
47
+ case 'win32':
48
+ command = 'cmd';
49
+ args = ['/c', 'start', url];
50
+ break;
51
+ default:
52
+ // Linux and others
53
+ command = 'xdg-open';
54
+ args = [url];
55
+ }
56
+ return new Promise((resolve, reject) => {
57
+ const child = spawn(command, args, {
58
+ detached: true,
59
+ stdio: 'ignore',
60
+ });
61
+ child.unref();
62
+ child.on('error', reject);
63
+ // Give it a moment to start
64
+ setTimeout(resolve, 500);
65
+ });
66
+ }
67
+ /**
68
+ * Login command - opens browser for authentication
69
+ */
70
+ async function login() {
71
+ console.log('Starting authentication flow...');
72
+ // Check if already logged in
73
+ const existing = await getStoredToken();
74
+ if (existing && !isTokenExpired(existing.token)) {
75
+ console.log(`Already logged in as ${existing.email || 'unknown user'}`);
76
+ console.log('Run "joan-mcp logout" first to login with a different account.');
77
+ return;
78
+ }
79
+ // Find available port for callback
80
+ const port = await findAvailablePort();
81
+ console.log(`Callback server listening on port ${port}`);
82
+ // Start callback server
83
+ const callbackPromise = startCallbackServer(port);
84
+ // Open browser to MCP auth page
85
+ const loginUrl = getMcpAuthUrl(port);
86
+ console.log(`Opening browser to: ${loginUrl}`);
87
+ console.log('If the browser does not open, please visit the URL manually.');
88
+ try {
89
+ await openBrowser(loginUrl);
90
+ }
91
+ catch (error) {
92
+ console.log('Could not open browser automatically.');
93
+ console.log(`Please visit: ${loginUrl}`);
94
+ }
95
+ console.log('\nWaiting for authentication...');
96
+ try {
97
+ const { token, email } = await callbackPromise;
98
+ // Parse JWT to get expiration
99
+ const payload = parseJwt(token);
100
+ const expiresAt = payload?.exp ? new Date(payload.exp * 1000) : undefined;
101
+ // Store the token
102
+ await storeToken(token, email, expiresAt);
103
+ console.log('\n✓ Authentication successful!');
104
+ console.log(` Logged in as: ${email || 'unknown'}`);
105
+ if (expiresAt) {
106
+ console.log(` Token expires: ${expiresAt.toLocaleDateString()}`);
107
+ }
108
+ console.log('\nYou can now use joan-mcp with Claude Code or other MCP clients.');
109
+ }
110
+ catch (error) {
111
+ console.error('\n✗ Authentication failed:', error.message);
112
+ process.exit(1);
113
+ }
114
+ }
115
+ /**
116
+ * Logout command - clear stored credentials
117
+ */
118
+ async function logout() {
119
+ await clearToken();
120
+ console.log('Logged out. Stored credentials have been cleared.');
121
+ }
122
+ /**
123
+ * Status command - show current auth status
124
+ */
125
+ async function status() {
126
+ // Check environment variable first
127
+ if (process.env.JOAN_AUTH_TOKEN) {
128
+ console.log('Authentication: Using JOAN_AUTH_TOKEN environment variable');
129
+ const payload = parseJwt(process.env.JOAN_AUTH_TOKEN);
130
+ if (payload) {
131
+ console.log(` Email: ${payload.sub || payload.email || 'unknown'}`);
132
+ if (payload.exp) {
133
+ const expDate = new Date(payload.exp * 1000);
134
+ const isExpired = expDate < new Date();
135
+ console.log(` Expires: ${expDate.toLocaleDateString()} ${isExpired ? '(EXPIRED)' : ''}`);
136
+ }
137
+ }
138
+ console.log(`\nAPI URL: ${getApiUrl()}`);
139
+ return;
140
+ }
141
+ // Check stored token
142
+ const stored = await getStoredToken();
143
+ if (!stored) {
144
+ console.log('Not logged in.');
145
+ console.log('Run "joan-mcp login" to authenticate.');
146
+ return;
147
+ }
148
+ const isExpired = isTokenExpired(stored.token);
149
+ console.log(`Authentication: Logged in${isExpired ? ' (EXPIRED)' : ''}`);
150
+ console.log(` Email: ${stored.email || 'unknown'}`);
151
+ if (stored.expiresAt) {
152
+ console.log(` Expires: ${stored.expiresAt.toLocaleDateString()}`);
153
+ }
154
+ console.log(`\nAPI URL: ${getApiUrl()}`);
155
+ // Verify token by calling API
156
+ if (!isExpired) {
157
+ try {
158
+ const config = await loadConfig();
159
+ const client = new JoanApiClient({
160
+ baseUrl: config.apiUrl,
161
+ authToken: config.authToken,
162
+ });
163
+ const user = await client.getCurrentUser();
164
+ console.log(`\n✓ Token verified with API`);
165
+ console.log(` User ID: ${user.id}`);
166
+ console.log(` Name: ${user.name || 'N/A'}`);
167
+ }
168
+ catch (error) {
169
+ console.log(`\n⚠ Could not verify token with API: ${error.message}`);
170
+ }
171
+ }
172
+ }
173
+ /**
174
+ * Serve command - start MCP server
175
+ */
176
+ async function serve() {
177
+ // This is handled by index.ts
178
+ await startServer();
179
+ }
180
+ /**
181
+ * Get the path to this CLI script for Claude Code config
182
+ */
183
+ function getCliPath() {
184
+ // Get the directory where this script is located
185
+ const scriptPath = process.argv[1];
186
+ // If running via tsx, we need to find the actual source file
187
+ if (scriptPath.includes('node_modules/.bin/tsx') || scriptPath.includes('tsx')) {
188
+ // We're running in dev mode, use the src path
189
+ const srcDir = new URL('.', import.meta.url).pathname;
190
+ return `${srcDir}cli.ts`;
191
+ }
192
+ // Running compiled, use the dist path
193
+ return scriptPath;
194
+ }
195
+ /**
196
+ * Configure Claude Code to use Joan MCP
197
+ */
198
+ async function configureClaudeCode() {
199
+ const { readFile, writeFile, mkdir } = await import('node:fs/promises');
200
+ const { homedir } = await import('node:os');
201
+ const { join, dirname } = await import('node:path');
202
+ const { existsSync } = await import('node:fs');
203
+ const claudeSettingsPath = join(homedir(), '.claude', 'settings.json');
204
+ const cliPath = getCliPath();
205
+ // Determine how to run the CLI
206
+ let command;
207
+ let args;
208
+ if (cliPath.endsWith('.ts')) {
209
+ // Development mode - use npx tsx
210
+ command = 'npx';
211
+ args = ['tsx', cliPath, 'serve'];
212
+ }
213
+ else {
214
+ // Production mode - use node directly
215
+ command = 'node';
216
+ args = [cliPath, 'serve'];
217
+ }
218
+ const joanConfig = {
219
+ command,
220
+ args,
221
+ };
222
+ try {
223
+ let settings = {};
224
+ // Read existing settings if they exist
225
+ if (existsSync(claudeSettingsPath)) {
226
+ const content = await readFile(claudeSettingsPath, 'utf8');
227
+ settings = JSON.parse(content);
228
+ }
229
+ else {
230
+ // Create directory if it doesn't exist
231
+ await mkdir(dirname(claudeSettingsPath), { recursive: true });
232
+ }
233
+ // Add or update mcpServers
234
+ if (!settings.mcpServers) {
235
+ settings.mcpServers = {};
236
+ }
237
+ settings.mcpServers.joan = joanConfig;
238
+ // Write updated settings
239
+ await writeFile(claudeSettingsPath, JSON.stringify(settings, null, 2), 'utf8');
240
+ console.log(`\n✓ Claude Code configured`);
241
+ console.log(` Settings: ${claudeSettingsPath}`);
242
+ console.log(` Command: ${command} ${args.join(' ')}`);
243
+ return true;
244
+ }
245
+ catch (error) {
246
+ console.error(`\n⚠ Could not configure Claude Code automatically: ${error.message}`);
247
+ console.log('\nManual configuration:');
248
+ console.log(`Add this to ${claudeSettingsPath}:`);
249
+ console.log(JSON.stringify({ mcpServers: { joan: joanConfig } }, null, 2));
250
+ return false;
251
+ }
252
+ }
253
+ /**
254
+ * Init command - full setup (login + configure Claude Code)
255
+ */
256
+ async function init() {
257
+ console.log('╔════════════════════════════════════════════╗');
258
+ console.log('║ Joan MCP Server - Setup Wizard ║');
259
+ console.log('╚════════════════════════════════════════════╝\n');
260
+ // Step 1: Check if already logged in
261
+ const existing = await getStoredToken();
262
+ if (existing && !isTokenExpired(existing.token)) {
263
+ console.log(`✓ Already logged in as ${existing.email || 'unknown user'}\n`);
264
+ }
265
+ else {
266
+ // Step 1: Login
267
+ console.log('Step 1/2: Authenticate with Joan\n');
268
+ await login();
269
+ console.log('');
270
+ }
271
+ // Step 2: Configure Claude Code
272
+ console.log('Step 2/2: Configure Claude Code\n');
273
+ await configureClaudeCode();
274
+ // Done!
275
+ console.log('\n╔════════════════════════════════════════════╗');
276
+ console.log('║ Setup Complete! ║');
277
+ console.log('╚════════════════════════════════════════════╝');
278
+ console.log('\nYou can now use Joan with Claude Code:');
279
+ console.log(' • "Show me my projects in Joan"');
280
+ console.log(' • "Create a task for implementing the login feature"');
281
+ console.log(' • "Mark task XYZ as completed"');
282
+ console.log('\nNote: Restart Claude Code for changes to take effect.');
283
+ }
284
+ /**
285
+ * Main CLI entry point
286
+ */
287
+ async function main() {
288
+ const args = process.argv.slice(2);
289
+ const command = args[0] || 'serve';
290
+ switch (command) {
291
+ case 'init':
292
+ await init();
293
+ break;
294
+ case 'login':
295
+ await login();
296
+ break;
297
+ case 'logout':
298
+ await logout();
299
+ break;
300
+ case 'status':
301
+ await status();
302
+ break;
303
+ case 'serve':
304
+ await serve();
305
+ break;
306
+ case 'help':
307
+ case '--help':
308
+ case '-h':
309
+ console.log(HELP_TEXT);
310
+ break;
311
+ case 'version':
312
+ case '--version':
313
+ case '-v':
314
+ console.log('joan-mcp v1.0.0');
315
+ break;
316
+ default:
317
+ console.error(`Unknown command: ${command}`);
318
+ console.log(HELP_TEXT);
319
+ process.exit(1);
320
+ }
321
+ }
322
+ main().catch((error) => {
323
+ console.error('Error:', error.message);
324
+ process.exit(1);
325
+ });
326
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}